Mutex in Java
In the world of computer science, Mutual exclusion or Mutex is known as a property of concurrency control. Every computer works the smallest sequence of programmed instruction known as thread. At one time, the computer works on a single thread. Let’s dive into some more aspects for a better understanding.
Threading and Multithreading
CPU works on threads for multitasking. Each process works by constantly shifting from thread to thread at a very fast speed. For instance, when we watch a video, the audio of the video is on a different thread, and the picture is on a different one. The constant switch between these two is very fast, and it is known as multithreading.
Threads in Java
Creating a thread in Java is done by extending a class and implementing an interface. Multithreading is a Java feature that permits the execution of two or more portions of a program simultaneously to maximize CPU efficiency. A thread is a component of such a program. Threads are hence lightweight processes within processes.
Mutex
Two or more threads may need to access a shared resource simultaneously in a multithreaded program, resulting in unexpected behavior. Data structures, input-output devices, files, and network connections are examples of shared resources.
It is referred to as a race condition. The key section of the program is the part of the program that accesses the shared resource. As a result, we must synchronize access to the critical portion to avoid a race condition.
The most basic sort of synchronizer is a mutex (or mutual exclusion), which assures that only one thread can run the essential area of a computer program at a time. It is implemented by a class called semaphore
.
A thread gets the mutex, then accesses the crucial section, and lastly releases the mutex to access a critical region. Meanwhile, all other threads are blocked until the mutex is released. A thread can enter the critical section as soon as it exits the critical area.
For mutex, there are two methods for locking and unlocking. They are known as acquire()
and release()
respectively. Now take a look at the example down below.
Learn more about Mutex here.
import java.util.LinkedList; // linked list import
import java.util.concurrent.Semaphore; // semaphore import
public class Mutex {
static LinkedList<String> WorkingQueue = new LinkedList<String>();
// track the record of works
static Semaphore mutex1 = new Semaphore(0); // creating a Semaphore To ImplementLogic
static Semaphore mutex = new Semaphore(1); // Creating A Mutex
}
In the above example, we made two Mutex objects with the name of mutex
and mutex1
. We’ll be using mutex1
to control the switch between two threads. The reason for creating the Linked List is to have a track record of threads. Now, let’s add two threads in the above code. Two threads with the name of Producer
and Consumer
.
import java.util.LinkedList; // linked list import
import java.util.concurrent.Semaphore; // semaphore import
public class Mutex {
static LinkedList<String> WorkingQueue = new LinkedList<String>();
// track the record of works
static Semaphore mutex1 = new Semaphore(0); // creating a Semaphore To ImplementLogic
static Semaphore mutex = new Semaphore(1); // Creating A Mutex
static class Producer extends Thread {
public void run() { // default run method of thread
int counter = 1;
try {
while (true) {
String threadName = Thread.currentThread().getName()
+ counter++; // counter is added to have the thread number being used
mutex.acquire(); // Acquiring Lock before Producing so the consumer cannot consume.
WorkingQueue.add(threadName);
System.out.println("Producer is prdoucing producing: " + threadName);
mutex.release(); // releasing After Production ;
mutex1.release(); // relesing lock for consumer...so consumer can consume after production
Thread.sleep(2000); // just to Reduce the Execution Speed
}
} catch (Exception e) { /*nothing */
}
}
}
static class Consumer extends Thread {
String consumerName;
public Consumer(String name) {
this.consumerName = name;
}
public void run() {
try {
while (true) {
mutex1.acquire(); /// Again Acquiring So no production while consuming
mutex.acquire(); // Acquring Other consumers lock one consume at one time
String result = "";
for (String value : WorkingQueue) {
result = value + ",";
}
System.out.println(consumerName + " consumes value: " + result
+ "Total Size working Queue Size " + WorkingQueue.size() + "\n");
mutex.release(); // releasing lock for other consumers.
}
} catch (Exception e) {
}
}
public static void main(String[] args) {
Producer producer = new Producer();
producer.start();
Consumer c1 = new Consumer("Bill Gates");
Consumer c2 = new Consumer("Jeff Bezoz");
Consumer c3 = new Consumer("Mark Zukerberg");
c1.start();
c2.start();
c3.start();
}
}
}
Explanation
The above code is self-explanatory as well, but this explanation will resolve the confusion.
Inside the Producer
Thread
When you run the above program, it will create a producer
thread. Inside that thread, there’s a while
loop that will run indefinite times. The string threadName
is just for displaying the thread execution. The object mutex
will acquire the lock for the consumer thread to be functional. (The main purpose of Mutex, getting control of concurrency).
After that, the producer
thread becomes functional. Then we have to release this thread for production. In the producer
thread, we’ll release mutex1
, the object responsible for handling the switch between consumer
and producer
. Upon release, the consumers will begin to consume, in other words, the consumer
thread will be functional.
Inside the Consumer
Thread
Right after we entered the consumer
thread, we acquired mutex1
to stop production during consumption. As you can see, we have created three consumers under the names C1
, C2
, and C3
. In order to allow one consumer to be functional at a single time, we also acquired mutex
.
After that, C1
will become functional, while C2
and C3
will be acquired. Upon completion, mutex
will be released again, allowing the other consumer to be functional.
This is how mutex works in Java. After running the above program. It will constantly show the current number of producer
threads being used, and the name of the consumer
using it.
The size will keep on increasing as the program runs.
Haider specializes in technical writing. He has a solid background in computer science that allows him to create engaging, original, and compelling technical tutorials. In his free time, he enjoys adding new skills to his repertoire and watching Netflix.
LinkedIn