JavaRush /Java Blog /Random EN /What is the difference between a mutex, a monitor and a s...

What is the difference between a mutex, a monitor and a semaphore

Published in the Random EN group
Hello! While studying multithreading in JavaRush, you often came across the concepts of “mutex” and “monitor”. Can you now, without peeking, answer how they differ? :) What is the difference between a mutex, a monitor and a semaphore - 1If you could, well done! If not (and most often this happens) - no wonder. The concepts of "mutex" and "monitor" are indeed related. Moreover, while reading lectures and watching videos on multithreading on external resources on the Internet, you will come across another similar concept - “semaphore”. Its functionality is also largely similar to a monitor and a mutex. Therefore, let’s understand these three terms, look at a few examples and finally organize in our heads the understanding of how they differ from each other :)

Mutex

A mutex is a special object for synchronizing threads. It is “attached” to every object in Java - you already know that :) It doesn’t matter whether you use standard classes or created your own classes, say, Catand Dog: all objects of all classes have a mutex . The name “mutex” comes from the English “MUTual EXclusion” - “mutual exclusion”, and this perfectly reflects its purpose. As we said in one of the previous lectures, the task of a mutex is to provide such a mechanism so that only one thread has access to an object at a certain time . A popular analogy for a mutex in real life is the “toilet example.” When a person enters the toilet, he locks the door from the inside. The toilet acts as an object that can be accessed by multiple threads. The lock on the toilet door is the role of a mutex, and the queue of people outside is the role of threads. The lock on the door is a toilet mutex: it ensures that only one person can be inside at a time. What is the difference between a mutex, a monitor and a semaphore - 2In other words, only one thread at a time can work on shared resources. Attempts by other threads (people) to access occupied resources will fail. A mutex has several important features. Firstly , only two states are possible - “free” and “busy”. This makes it easier to understand how it works: parallels can be drawn with Boolean variables true/false or the binary number system 1/0. Secondly , states cannot be controlled directly. There are no mechanisms in Java that would allow you to explicitly take an object, get its mutex and assign the desired status to it. In other words, you can't do something like:
Object myObject = new Object();
Mutex mutex = myObject.getMutex();
mutex.free();
Thus, the object's mutex cannot be released. Only the Java machine has direct access to it. Programmers work with mutexes using language tools.

Monitor

A monitor is an additional “add-on” to a mutex. In fact, the monitor is a piece of code “invisible” to the programmer . Speaking about the mutex earlier, we gave a simple example:
public class Main {

   private Object obj = new Object();

   public void doSomething() {

       //...some logic available to all threads

       synchronized (obj) {

           //logic that is only available to one thread at a time
       }
   }
}
In the block of code that is marked with the word synchronized, the mutex of our object is captured obj. Okay, the capture happens, but how exactly is the “defense mechanism” achieved? synchronizedWhy can't other threads go inside the block when they see a word ? It is the monitor that creates the protective mechanism! The compiler converts the word synchronizedinto several special pieces of code. Once again let's return to our example with the method doSomething()and add to it:
public class Main {

   private Object obj = new Object();

   public void doSomething() {

       //...some logic available to all threads

       //logic that is only available to one thread at a time
       synchronized (obj) {

           /*выполнить важную работу, при которой доступ к an objectу
           должен быть только у одного потока*/
           obj.someImportantMethod();
       }
   }
}
Here's what will happen "under the hood" of our program after the compiler converts this code:
public class Main {

   private Object obj = new Object();

   public void doSomething() throws InterruptedException {

       //...some logic available to all threads

       //логика, которая одновременно доступна только для одного потока:

       /*до тех пор, пока мьютекс an object занят -
       любой другой поток (кроме того, который его захватил), спит*/
       while (obj.getMutex().isBusy()) {
           Thread.sleep(1);
       }

       //пометить мьютекс an object How занятый
       obj.getMutex().isBusy() = true;

       /*выполнить важную работу, при которой доступ к an objectу
       должен быть только у одного потока*/
       obj.someImportantMethod();

       //освободить мьютекс an object
       obj.getMutex().isBusy() = false;
   }
}
The example is, of course, not real. Here, using Java-like code, we tried to reflect what is happening at this moment inside the Java machine. However, this pseudocode gives a great understanding of what is actually happening with the object and threads inside the block synchronizedand how the compiler converts this word into several commands that are “invisible” to the programmer. Essentially, monitor in Java is expressed using the wordsynchronized . All the code that appeared instead of the word synchronizedin the last example is the monitor.

Semaphore

Another word that you come across when studying multithreading on your own is “semaphore”. Let's figure out what it is and how it differs from a monitor and a mutex. A semaphore is a means for synchronizing access to a resource. Its peculiarity is that it uses a counter when creating a synchronization mechanism. The counter tells us how many threads can simultaneously access a shared resource. What is the difference between a mutex, a monitor and a semaphore - 3Semaphores in Java are represented by the class Semaphore. When creating semaphore objects, we can use the following constructors:
Semaphore(int permits)
Semaphore(int permits, boolean fair)
We pass to the constructor:
  • int permits— initial and maximum counter value. That is, how many threads can simultaneously access a shared resource;

  • boolean fair- to establish the order in which threads will receive access. If fair= true , access is granted to waiting threads in the order in which they requested it. If it is false , the order will be determined by the thread scheduler.

A classic example of the use of semaphores is the lunching philosophers problem .
What is the difference between a mutex, a monitor and a semaphore - 4
We will simplify its terms a little for better understanding. Imagine we have 5 philosophers who need lunch. At the same time, we have one table, and no more than two people can be at it at the same time. Our task is to feed all philosophers. Neither of them should go hungry, nor should they “block” each other when trying to sit down at the table (we must avoid deadlock). This is what our philosopher class will look like:
class Philosopher extends Thread {

   private Semaphore sem;

   // поел ли философ
   private boolean full = false;

   private String name;

   Philosopher(Semaphore sem, String name) {
       this.sem=sem;
       this.name=name;
   }

   public void run()
   {
       try
       {
           // если философ еще не ел
           if (!full) {
               //Запрашиваем у семафора разрешение на выполнение
               sem.acquire();
               System.out.println (name + " садится за стол");

               // философ ест
               sleep(300);
               full = true;

               System.out.println (name + " поел! Он выходит из-за стола");
               sem.release();

               // философ ушел, освободив место другим
               sleep(300);
           }
       }
       catch(InterruptedException e) {
           System.out.println ("What-то пошло не так!");
       }
   }
}
And here is the code to run our program:
public class Main {

   public static void main(String[] args) {

       Semaphore sem = new Semaphore(2);
       new Philosopher(sem,"Сократ").start();
       new Philosopher(sem,"Платон").start();
       new Philosopher(sem,"Аристотель").start();
       new Philosopher(sem,"Фалес").start();
       new Philosopher(sem,"Пифагор").start();
   }
}
We created a semaphore with a count of 2 to satisfy the condition that only two philosophers can eat at the same time. That is, only two threads can work simultaneously, because our class Philosopheris inherited from Thread! The class's acquire()and methods control its permission counter. The method requests permission to access a resource from the semaphore. If counter > 0, the permission is granted and the counter is decremented by 1. The method "releases" the previously granted permission and returns it to the counter (incrementing the semaphore's grant counter by 1). What do we get when we run the program? Has the problem been solved? Will our philosophers fight while waiting for their turn? :) This is the console output we received: Socrates sits down at the table Plato sits down at the table Socrates has eaten! He leaves the table. Plato has eaten! He leaves the table Aristotle sits down at the table Pythagoras sits down at the table Aristotle has eaten! He leaves the table Pythagoras has eaten! He leaves the table Thales sits down at the table Thales has eaten! He leaves the table. We succeeded! And although Thales had to dine alone, I think he’s not mad at us :) You may have noticed some similarities between a mutex and a semaphore. In general, they have the same purpose: to synchronize access to some resource. The only difference is that an object’s mutex can only be acquired by one thread at a time, while in the case of a semaphore, a thread counter is used, and several of them can access the resource at once. And this is not just a coincidental similarity :) In fact, a mutex is a single-place semaphore . That is, it is a semaphore whose counter is initially set to 1. It is also called a “binary semaphore” because its counter can only have 2 values ​​- 1 (“free”) and 0 (“busy”). That's all! As you can see, everything turned out to be not so confusing :) Now, if you want to study the topic of multithreading in more detail on the Internet, it will be a little easier for you to navigate the concepts. See you in the next lessons! release()Semaphoreacquire()release()What is the difference between a mutex, a monitor and a semaphore - 5
Comments
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION