Mutex in Java

Haider Ali Oct 12, 2023
  1. Threading and Multithreading
  2. Threads in Java
  3. Mutex
  4. Explanation
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.

java mutex example

The size will keep on increasing as the program runs.

Author: Haider Ali
Haider Ali avatar Haider Ali avatar

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

Related Article - Java Threading