JavaRush /Blog Java /Random-VI /Sự khác biệt giữa mutex, màn hình và semaphore

Sự khác biệt giữa mutex, màn hình và semaphore

Xuất bản trong nhóm
Xin chào! Khi nghiên cứu đa luồng trong JavaRush, bạn thường gặp các khái niệm về “mutex” và “monitor”. Bây giờ bạn có thể trả lời mà không cần nhìn trộm chúng khác nhau như thế nào không? :) В чем разница между мьютексом, монитором и семафором - 1Nếu bạn có thể, làm tốt lắm! Nếu không (và điều này thường xảy ra nhất) - không có gì lạ. Các khái niệm "mutex" và "màn hình" thực sự có liên quan với nhau. Hơn nữa, khi đọc các bài giảng và xem video về đa luồng trên các tài nguyên bên ngoài trên Internet, bạn sẽ bắt gặp một khái niệm tương tự khác - “semaphore”. Chức năng của nó cũng phần lớn tương tự như màn hình và mutex. Do đó, hãy hiểu ba thuật ngữ này, xem xét một vài ví dụ và cuối cùng sắp xếp trong đầu chúng ta sự hiểu biết về sự khác biệt của chúng :)

Mutex

Mutex là một đối tượng đặc biệt để đồng bộ hóa các luồng. Nó được “đính kèm” với mọi đối tượng trong Java - bạn đã biết điều đó rồi :) Không quan trọng bạn sử dụng các lớp tiêu chuẩn hay tạo các lớp của riêng mình, chẳng hạn, CatDog: tất cả các đối tượng của tất cả các lớp đều có một mutex . Cái tên “mutex” xuất phát từ tiếng Anh “MUTual EXclusion” - “loại trừ lẫn nhau” và điều này phản ánh hoàn hảo mục đích của nó. Như chúng tôi đã nói trong một trong những bài giảng trước, nhiệm vụ của mutex là cung cấp một cơ chế sao cho chỉ một luồng có quyền truy cập vào một đối tượng tại một thời điểm nhất định . Một ví dụ tương tự phổ biến về mutex trong đời thực là “ví dụ về nhà vệ sinh”. Khi một người vào nhà vệ sinh, anh ta sẽ khóa cửa từ bên trong. Nhà vệ sinh hoạt động như một đối tượng có thể được truy cập bởi nhiều luồng. Ổ khóa trên cửa nhà vệ sinh đóng vai trò là một mutex, còn dòng người xếp hàng bên ngoài đóng vai trò là sợi dây. Khóa trên cửa là một loại khóa bí mật trong nhà vệ sinh: nó đảm bảo rằng mỗi lần chỉ có một người có thể vào bên trong. В чем разница между мьютексом, монитором и семафором - 2Nói cách khác, tại một thời điểm chỉ có một luồng có thể hoạt động trên các tài nguyên được chia sẻ. Nỗ lực của các chủ đề khác (người) để truy cập tài nguyên bị chiếm dụng sẽ không thành công. Một mutex có một số tính năng quan trọng. Thứ nhất , chỉ có thể có hai trạng thái - “rảnh” và “bận”. Điều này giúp bạn hiểu cách thức hoạt động của nó dễ dàng hơn: các phép so sánh có thể được vẽ bằng các biến Boolean đúng/sai hoặc hệ thống số nhị phân 1/0. Thứ hai , các quốc gia không thể được kiểm soát trực tiếp. Không có cơ chế nào trong Java cho phép bạn lấy một đối tượng một cách rõ ràng, lấy mutex của nó và gán trạng thái mong muốn cho nó. Nói cách khác, bạn không thể làm điều gì đó như:
Object myObject = new Object();
Mutex mutex = myObject.getMutex();
mutex.free();
Vì vậy, mutex của đối tượng không thể được giải phóng. Chỉ có máy Java mới có quyền truy cập trực tiếp vào nó. Các lập trình viên làm việc với mutexes bằng các công cụ ngôn ngữ.

Màn hình

Màn hình là một “tiện ích bổ sung” bổ sung cho mutex. Trên thực tế, màn hình là một đoạn mã “vô hình” đối với người lập trình . Nói về mutex trước đó, chúng tôi đã đưa ra một ví dụ đơn giản:
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
       }
   }
}
В code block, который помечен словом synchronized, происходит захват мьютекса нашего an object obj. Хорошо, захват-то происходит, но How именно обеспечивается «защитный механизм»? Почему при виде слова synchronized остальные потоки не могут пройти внутрь блока? Защитный механизм создает именно монитор! Компилятор преобразует слово synchronized в несколько специальных кусков codeа. Еще раз вернемся к нашему примеру с методом doSomething() и дополним его:
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();
       }
   }
}
Вот что будет происходить «под капотом» нашей программы после того, How компилятор преобразует этот 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;
   }
}
Пример, конечно, ненастоящий. Здесь мы с помощью Java-подобного codeа попытались отразить то, что происходит в этот момент внутри Java-машины. Однако этот псевдоcode дает отличное понимание того, что на самом деле происходит с an objectом и потоками внутри блока synchronized и How компилятор преобразует это слово в несколько «невидимых» для программиста команд. По сути, монитор в Java выражен с помощью слова synchronized. Весь code, который появился instead of слова synchronized в последнем примере, — это и есть монитор.

Семафор

Еще одно слово, с которым ты сталкиваешься при самостоятельном изучении многопоточности — «семафор». Давай разберемся что это такое, и чем он отличается от монитора и мьютекса. Семафор — это средство для синхронизации доступа к Howому-то ресурсу. Его особенность заключается в том, что при создании механизма синхронизации он использует счетчик. Счетчик указывает нам, сколько потоков одновременно могут получать доступ к общему ресурсу. В чем разница между мьютексом, монитором и семафором - 3Семафоры в Java представлены классом Semaphore. При создании an objectов-семафоров мы можем использовать такие конструкторы:
Semaphore(int permits)
Semaphore(int permits, boolean fair)
В конструктор мы передаем:
  • int permits — начальное и максимальное meaning счетчика. То есть то, сколько потоков одновременно могут иметь доступ к общему ресурсу;

  • boolean fair — для установления порядка, в котором потоки будут получать доступ. Если fair = true, доступ предоставляется ожидающим потокам в том порядке, в котором они его запрашивали. Если же он equals false, порядок будет определять планировщик потоков.

Классический пример использования семафоров — задача об обедающих философах.
В чем разница между мьютексом, монитором и семафором - 4
Мы немного упростим ее условия, для лучшего понимания. Представь, что у нас есть 5 философов, которым нужно пообедать. При этом у нас есть один стол, и одновременно находиться за ним могут не более двух человек. Наша задача — накормить всех философов. Никто из них не должен остаться голодным, и при этом они не должны «заблокировать» друг друга при попытке сесть за стол (мы должны избежать deadlock). Вот How будет выглядеть наш класс философа:
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-то пошло не так!");
       }
   }
}
А вот code для запуска нашей программы:
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();
   }
}
Мы создали семафор со счетчиком 2, чтобы соответствовать условию: одновременно есть могут только два философа. То есть, одновременно работать могут только два потока, ведь наш класс Philosopher унаследован от Thread! Методы acquire() и release() класса Semaphore управляют его счетчиком разрешений. Метод acquire() запрашивает разрешение на доступ к ресурсу у семафора. Если счетчик > 0, разрешение предоставляется, а счетчик уменьшается на 1. Метод release() «освобождает» выданное ранее разрешение и возвращает его в счетчик (увеличивает счетчик разрешений семафора на 1). What же у нас получится при запуске программы? Решена ли задача, не передерутся ли наши философы, ожидая своей очереди? :) Вот Howой вывод в консоль мы получor: Сократ садится за стол Платон садится за стол Сократ поел! Он выходит из-за стола Платон поел! Он выходит из-за стола Аристотель садится за стол Пифагор садится за стол Аристотель поел! Он выходит из-за стола Пифагор поел! Он выходит из-за стола Фалес садится за стол Фалес поел! Он выходит из-за стола У нас все получилось! И хотя Фалесу пришлось обедать в одиночку, думаю, он на нас не в обиде :) Ты мог заметить некоторое сходство между мьютексом и семафором. У них, в общем-то, одинаковое преднаmeaning: синхронизировать доступ к Howому-то ресурсу. В чем разница между мьютексом, монитором и семафором - 5Difference только в том, что мьютекс an object может захватить одновременно только один поток, а в случае с семафором используется счетчик потоков, и доступ к ресурсу могут получить сразу несколько из них. И это не просто случайное сходство :) На самом деле мьютекс — это одноместный семафор. То есть, это семафор, счетчик которого изначально установлен в значении 1. Его еще называют «двоичным семафором», поскольку его счетчик может иметь только 2 значения — 1 («свободно») и 0 («занято»). Вот и все! Как видишь, все оказалось не таким уж и запутанным :) Теперь, если ты захочешь изучить тему многопоточности подробнее в Интернете, тебе будет чуть проще ориентироваться в понятиях. До встречи на следующих уроках!
Bình luận
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION