JavaRush /Blogue Java /Random-PT /Qual é a diferença entre um mutex, um monitor e um semáfo...

Qual é a diferença entre um mutex, um monitor e um semáforo

Publicado no grupo Random-PT
Olá! Ao estudar multithreading no JavaRush, você frequentemente se deparou com os conceitos de “mutex” e “monitor”. Você pode agora, sem espiar, responder como eles diferem? :) Qual é a diferença entre um mutex, um monitor e um semáforo - 1Se você pudesse, muito bem! Se não (e na maioria das vezes isso acontece) - não é de admirar. Os conceitos de “mutex” e “monitor” estão realmente relacionados. Além disso, ao ler palestras e assistir a vídeos sobre multithreading em recursos externos na Internet, você encontrará outro conceito semelhante - “semáforo”. Sua funcionalidade também é bastante semelhante a um monitor e um mutex. Portanto, vamos entender esses três termos, olhar alguns exemplos e por fim organizar em nossas cabeças o entendimento de como eles se diferenciam :)

Mutex

Um mutex é um objeto especial para sincronizar threads. Ele está “anexado” a todos os objetos em Java - você já sabe disso :) Não importa se você usa classes padrão ou cria suas próprias classes, digamos, Cate Dog: todos os objetos de todas as classes têm um mutex . O nome “mutex” vem do inglês “MUTual EXclusion” - “exclusão mútua”, e isso reflete perfeitamente o seu propósito. Como dissemos em uma das palestras anteriores, a tarefa de um mutex é fornecer tal mecanismo para que apenas um thread tenha acesso a um objeto em um determinado momento . Uma analogia popular para um mutex na vida real é o “exemplo do banheiro”. Quando uma pessoa entra no banheiro, ela tranca a porta por dentro. O banheiro atua como um objeto que pode ser acessado por vários threads. A fechadura da porta do banheiro desempenha o papel de mutex, e a fila de pessoas do lado de fora desempenha o papel de threads. A fechadura da porta é um mutex de banheiro: garante que apenas uma pessoa possa entrar por vez. Qual é a diferença entre um mutex, um monitor e um semáforo - 2Em outras palavras, apenas um thread por vez pode trabalhar em recursos compartilhados. As tentativas de outros threads (pessoas) de acessar recursos ocupados falharão. Um mutex possui vários recursos importantes. Em primeiro lugar , apenas dois estados são possíveis – “livre” e “ocupado”. Isso torna mais fácil entender como funciona: paralelos podem ser traçados com variáveis ​​booleanas verdadeiro/falso ou com o sistema numérico binário 1/0. Em segundo lugar , os Estados não podem ser controlados directamente. Não existem mecanismos em Java que permitam pegar explicitamente um objeto, obter seu mutex e atribuir o status desejado a ele. Em outras palavras, você não pode fazer algo como:
Object myObject = new Object();
Mutex mutex = myObject.getMutex();
mutex.free();
Assim, o mutex do objeto não pode ser liberado. Somente a máquina Java tem acesso direto a ele. Os programadores trabalham com mutexes usando ferramentas de linguagem.

Monitor

Um monitor é um “complemento” adicional para um mutex. Na verdade, o monitor é um trecho de código “invisível” para o programador . Falando sobre o mutex anteriormente, demos um exemplo simples:
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
       }
   }
}
No bloco de código marcado com a palavra synchronized, o mutex do nosso objeto é capturado obj. Ok, a captura acontece, mas como exatamente o “mecanismo de defesa” é alcançado? synchronizedPor que outros threads não podem entrar no bloco quando veem uma palavra ? É o monitor que cria o mecanismo de proteção! O compilador converte a palavra synchronizedem vários trechos especiais de código. Mais uma vez, vamos retornar ao nosso exemplo com o método doSomething()e adicionar a ele:
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();
       }
   }
}
Aqui está o que acontecerá "nos bastidores" do nosso programa depois que o compilador converter este código:
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;
   }
}
O exemplo, claro, não é real. Aqui, usando código semelhante ao Java, tentamos refletir o que está acontecendo neste momento dentro da máquina Java. Porém, esse pseudocódigo dá uma ótima compreensão do que realmente está acontecendo com o objeto e threads dentro do bloco synchronizede como o compilador converte essa palavra em diversos comandos que são “invisíveis” para o programador. Essencialmente, monitor em Java é expresso usando a palavrasynchronized . Todo o código que apareceu no lugar da palavra synchronizedno último exemplo é o monitor.

Semáforo

Outra palavra que você encontra ao estudar multithreading por conta própria é “semáforo”. Vamos descobrir o que é e como difere de um monitor e de um mutex. Um semáforo é um meio de sincronizar o acesso a um recurso. Sua peculiaridade é que utiliza um contador ao criar um mecanismo de sincronização. O contador nos informa quantos threads podem acessar simultaneamente um recurso compartilhado. Qual é a diferença entre um mutex, um monitor e um semáforo - 3Semáforos em Java são representados pela classe Semaphore. Ao criar objetos semáforo, podemos usar os seguintes construtores:
Semaphore(int permits)
Semaphore(int permits, boolean fair)
Passamos para o construtor:
  • int permits— valor inicial e máximo do contador. Ou seja, quantos threads podem acessar simultaneamente um recurso compartilhado;

  • boolean fair- estabelecer a ordem em que os threads receberão acesso. If fair= true , o acesso é concedido aos threads em espera na ordem em que eles o solicitaram. Se for false , a ordem será determinada pelo agendador de threads.

Um exemplo clássico do uso de semáforos é o problema dos filósofos almoçando .
Qual é a diferença entre um mutex, um monitor e um semáforo - 4
Vamos simplificar um pouco seus termos para melhor compreensão. Imagine que temos 5 filósofos que precisam de almoçar. Ao mesmo tempo, temos uma mesa e não podem estar mais do que duas pessoas ao mesmo tempo. Nossa tarefa é alimentar todos os filósofos. Nenhum deles deve passar fome, nem “bloquear” um ao outro ao tentar sentar-se à mesa (devemos evitar impasses). Esta é a aparência da nossa aula de filósofos:
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-то пошло не так!");
       }
   }
}
E aqui está o código para executar nosso programa:
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();
   }
}
Criamos um semáforo com contagem de 2 para satisfazer a condição de que apenas dois filósofos podem comer ao mesmo tempo. Ou seja, apenas duas threads podem funcionar simultaneamente, pois nossa classe Philosopheré herdada de Thread! A classe acquire()e os métodos controlam seu contador de permissões. O método solicita permissão para acessar um recurso do semáforo. Se contador > 0, a permissão é concedida e o contador é decrementado em 1. O método "libera" a permissão anteriormente concedida e a retorna ao contador (incrementando em 1 o contador de concessões do semáforo). O que obtemos quando executamos o programa? O problema foi resolvido? Nossos filósofos lutarão enquanto esperam pela sua vez? :) Este é o resultado do console que recebemos: Sócrates senta-se à mesa Platão senta-se à mesa que Sócrates comeu! Ele sai da mesa: Platão comeu! Ele sai da mesa Aristóteles senta-se à mesa Pitágoras senta-se à mesa que Aristóteles comeu! Ele sai da mesa que Pitágoras comeu! Ele sai da mesa que Thales se senta à mesa que Thales comeu! Ele sai da mesa. Conseguimos! E embora Thales tenha jantado sozinho, acho que ele não está bravo conosco :) Você deve ter notado algumas semelhanças entre um mutex e um semáforo. Em geral, eles têm a mesma finalidade: sincronizar o acesso a algum recurso. A única diferença é que o mutex de um objeto só pode ser adquirido por uma thread por vez, enquanto no caso de um semáforo é utilizado um contador de threads, e várias delas podem acessar o recurso ao mesmo tempo. E isso não é apenas uma semelhança coincidente :) Na verdade, um mutex é um semáforo de lugar único . Ou seja, é um semáforo cujo contador é inicialmente definido como 1. Também é chamado de “semáforo binário” porque seu contador só pode ter 2 valores – 1 (“livre”) e 0 (“ocupado”). Isso é tudo! Como você pode ver, tudo acabou não sendo tão confuso :) Agora, se você quiser estudar mais detalhadamente o tema multithreading na Internet, será um pouco mais fácil navegar pelos conceitos. Nos vemos nas próximas aulas! release()Semaphoreacquire()release()Qual é a diferença entre um mutex, um monitor e um semáforo - 5
Comentários
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION