CodeGym /Java Blog /무작위의 /뮤텍스, 모니터 및 세마포어의 차이점
John Squirrels
레벨 41
San Francisco

뮤텍스, 모니터 및 세마포어의 차이점

무작위의 그룹에 게시되었습니다
안녕! CodeGym에서 멀티스레딩을 공부할 때 "뮤텍스"와 "모니터"의 개념을 자주 접했습니다. 엿보지 않고 어떻게 다른지 말할 수 있습니까? :) 그렇다면 잘하셨습니다! 그렇지 않은 경우(이것이 가장 일반적임) 놀라운 일이 아닙니다. "뮤텍스"와 "모니터"는 실제로 관련된 개념입니다. 또한 다른 웹사이트에서 멀티스레딩에 대한 강의를 읽고 비디오를 볼 때 "세마포어"라는 또 다른 유사한 개념을 보게 될 것입니다. 또한 모니터 및 뮤텍스와 매우 유사한 기능을 가지고 있습니다. 이것이 우리가 이 세 가지 용어를 조사하는 이유입니다. 몇 가지 예를 살펴보고 이러한 개념이 서로 어떻게 다른지 확실하게 이해하게 될 것입니다. :)

뮤텍스

뮤텍스(또는 잠금)는 스레드 동기화를 위한 특수 메커니즘입니다. 하나는 Java의 모든 개체에 "연결"되어 있습니다. 여러분은 이미 알고 있습니다 :) 표준 클래스를 사용하든 자신만의 클래스를 생성하든 상관 없습니다. 예를 들어 Cat Dog : 모든 클래스의 모든 개체에는 뮤텍스가 있습니다 . "뮤텍스"라는 용어는 그 목적을 완벽하게 설명하는 "MUTual EXclusion"에서 유래했습니다. 이전 수업 중 하나에서 말했듯 이 뮤텍스를 사용하면 한 번에 하나의 스레드만 개체에 액세스할 수 있습니다. 뮤텍스의 인기 있는 실제 사례는 화장실과 관련이 있습니다. 사람이 변기 칸막이에 들어가면 안쪽에서 문을 잠급니다. 화장실은 여러 스레드에서 액세스할 수 있는 개체와 같습니다. 파티션 도어의 잠금 장치는 뮤텍스와 같으며 외부 사람들의 줄은 스레드를 나타냅니다. 문에 있는 자물쇠는 화장실의 뮤텍스입니다. 한 사람만 안으로 들어갈 수 있도록 합니다. 뮤텍스, 모니터 및 세마포어의 차이점은 무엇입니까?  - 2즉, 한 번에 하나의 스레드만 공유 리소스로 작업할 수 있습니다. 점유된 리소스에 대한 액세스 권한을 얻으려는 다른 스레드(사람)의 시도는 실패합니다. 뮤텍스에는 몇 가지 중요한 기능이 있습니다. 첫째 , "잠금 해제"와 "잠김"의 두 가지 상태만 가능합니다. 이는 작동 방식을 이해하는 데 도움이 됩니다. 부울 변수(참/거짓) 또는 이진수(0/1)를 사용하여 평행을 그릴 수 있습니다. , 상태를 직접 제어할 수 없습니다. Java에는 명시적으로 개체를 가져오고, 뮤텍스를 가져오고, 원하는 상태를 할당할 수 있는 메커니즘이 없습니다. 즉, 다음과 같은 작업을 수행할 수 없습니다.

Object myObject = new Object();
Mutex mutex = myObject.getMutex();
mutex.free();
즉, 개체의 뮤텍스를 해제할 수 없습니다. Java 머신만이 직접 액세스할 수 있습니다. 프로그래머는 언어 도구를 통해 뮤텍스를 사용합니다.

감시 장치

모니터는 뮤텍스에 대한 추가 "상부 ​​구조"입니다. 실제로 모니터는 프로그래머에게 "보이지 않는" 코드 덩어리입니다. 이전에 뮤텍스에 대해 이야기했을 때 간단한 예를 들었습니다.

public class Main {

   private Object obj = new Object();

   public void doSomething() {

       // ...some logic, available for all threads

       synchronized (obj) {

           // Logic available to just one thread at a time
       }
   }
}
synchronized 키워드 로 표시된 코드 블록에서 obj 개체 의 뮤텍스를 획득합니다. 좋아, 우리는 자물쇠를 얻을 수 있지만 정확히 어떻게 "보호"가 제공됩니까? synchronized 라는 단어가 표시되면 다른 스레드가 블록에 진입하는 것을 막는 것은 무엇입니까? 보호는 모니터에서 나옵니다! 컴파일러는 동기화된 키워드를 몇 가지 특수 코드 조각으로 변환합니다. 다시 한 번 doSomething() 메서드가 있는 예제로 돌아가겠습니다 . 우리는 그것에 추가할 것입니다:

public class Main {

   private Object obj = new Object();

   public void doSomething() {

       // ...some logic, available for all threads

       // Logic available to just one thread at a time
       synchronized (obj) {

           /* Do important work that requires that the object
           be accessed by only one thread */
           obj.someImportantMethod();
       }
   }
}
다음은 컴파일러가 이 코드를 변환한 후 "내부적으로" 일어나는 일입니다.

public class Main {

   private Object obj = new Object();

   public void doSomething() throws InterruptedException {

       // ...some logic, available for all threads

       // Logic available to just one thread at a time:
     
       /* as long as the object's mutex is busy,
       all the other threads (except the one that acquired it) are put to sleep */
       while (obj.getMutex().isBusy()) {
           Thread.sleep(1);
       }

       // Mark the object's mutex as busy
       obj.getMutex().isBusy() = true;

       /* Do important work that requires that the object
       be accessed by only one thread */
       obj.someImportantMethod();

       // Free the object's mutex
       obj.getMutex().isBusy() = false;
   }
}
물론 이것은 실제 사례가 아닙니다. 여기서 우리는 자바 머신 내부에서 일어나는 일을 묘사하기 위해 자바와 유사한 코드를 사용했습니다. 즉, 이 의사 코드는 동기화된 블록 내부의 개체 및 스레드에서 실제로 발생하는 일과 컴파일러가 이 키워드를 프로그래머에게 "보이지 않는" 여러 명령문으로 변환하는 방법에 대한 탁월한 이해를 제공합니다. 기본적으로 Java는 synchronized 키워드를 사용하여 모니터를 나타냅니다 . 마지막 예제에서 synchronized 키워드 대신 나타나는 코드는 모두 모니터입니다.

신호기

멀티스레딩에 대한 개인적인 연구에서 접하게 될 또 다른 단어는 "세마포어"입니다. 이것이 무엇이며 모니터 및 뮤텍스와 어떻게 다른지 알아봅시다. 세마포어는 일부 리소스에 대한 액세스를 동기화하는 도구입니다. 그것의 독특한 특징은 카운터를 사용하여 동기화 메커니즘을 생성한다는 것입니다. 카운터는 공유 리소스에 동시에 액세스할 수 있는 스레드 수를 알려줍니다. Java의 세마포어는 Semaphore뮤텍스, 모니터 및 세마포어의 차이점은 무엇입니까?  - 삼 클래스 로 표시됩니다 . 세마포어 개체를 만들 때 다음 생성자를 사용할 수 있습니다.

Semaphore(int permits)
Semaphore(int permits, boolean fair)
다음을 생성자에 전달합니다.
    int permits — 카운터의 초기값과 최대값. 즉, 이 매개변수는 공유 리소스에 동시에 액세스할 수 있는 스레드 수를 결정합니다.
  • boolean fair — 스레드가 액세스 권한을 얻는 순서를 설정합니다. fair 가 참 이면요청한 순서대로 대기 중인 스레드에 대한 액세스 권한이 부여됩니다. 거짓이면 스레드 스케줄러에 의해 순서가 결정됩니다.
세마포어 사용의 고전적인 예는 식사하는 철학자 문제입니다. 뮤텍스, 모니터 및 세마포어의 차이점은 무엇입니까?  - 4이해를 돕기 위해 조금 단순화하겠습니다. 점심을 먹어야 하는 5명의 철학자가 있다고 상상해 보십시오. 또한 두 명 이상 동시에 수용할 수 있는 테이블이 하나 있습니다. 우리의 임무는 모든 철학자를 먹이는 것입니다. 그들 중 누구도 배고프지 않아야 하며, 테이블에 앉으려고 할 때 서로 "차단"해서는 안 됩니다(교착 상태를 피해야 합니다). 철학자 수업은 다음과 같습니다.

class Philosopher extends Thread {

   private Semaphore sem;

   // Did the philosopher eat?
   private boolean full = false;

   private String name;

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

   public void run()
   {
       try
       {
           // If the philosopher has not eaten
           if (!full) {
               // Ask the semaphore for permission to run
               sem.acquire();
               System.out.println(name + " takes a seat at the table");

               // The philosopher eats
               sleep(300);
               full = true;

               System.out.println(name + " has eaten! He leaves the table");
               sem.release();

               // The philosopher leaves, making room for others
               sleep(300);
           }
       }
       catch(InterruptedException e) {
           System.out.println("Something went wrong!");
       }
   }
}
프로그램을 실행하는 코드는 다음과 같습니다.

public class Main {

   public static void main(String[] args) {

       Semaphore sem = new Semaphore(2);
       new Philosopher(sem, "Socrates").start();
       new Philosopher(sem,"Plato").start();
       new Philosopher(sem,"Aristotle").start();
       new Philosopher(sem, "Thales").start();
       new Philosopher(sem, "Pythagoras").start();
   }
}
우리는 조건을 만족시키기 위해 카운터가 2로 설정된 세마포어를 만들었습니다. 두 명의 철학자만 동시에 먹을 수 있습니다. 즉, Philosopher 클래스가 Thread 를 상속하기 때문에 동시에 두 개의 스레드만 실행할 수 있습니다 ! Semaphore 클래스의 capture ()release() 메서드는 액세스 카운터를 제어합니다. Acquire() 메서드는 세마포어에 리소스에 대한 액세스를 요청합니다. 카운터가 >0이면 액세스가 허용되고 카운터가 1 감소합니다. release ()메서드는 이전에 부여된 액세스를 "해제"하여 카운터로 반환합니다(세마포어의 액세스 카운터를 1씩 증가). 프로그램을 실행하면 무엇을 얻을 수 있습니까? 문제가 해결되었습니까? 우리 철학자들은 차례를 기다리면서 싸우지 않을까요? :) 우리가 얻은 콘솔 출력은 다음과 같습니다.

Socrates takes a seat at the table 
Plato takes a seat at the table 
Socrates has eaten! He leaves the table 
Plato has eaten! He leaves the table 
Aristotle takes a seat at the table 
Pythagoras takes a seat at the table 
Aristotle has eaten! He leaves the table 
Pythagoras has eaten! He leaves the table 
Thales takes a seat at the table 
Thales has eaten! He leaves the table 
우리는 해냈다! 그리고 Thales는 혼자 식사를 해야 했지만 우리가 그를 화나게 했다고 생각하지 않습니다. :) 뮤텍스와 세마포어 사이의 유사점을 눈치챘을 것입니다. 사실, 그들은 동일한 임무를 가지고 있습니다. 일부 리소스에 대한 액세스를 동기화하는 것입니다. 뮤텍스, 모니터 및 세마포어의 차이점은 무엇입니까?  - 5유일한 차이점은 개체의 뮤텍스는 한 번에 하나의 스레드에서만 얻을 수 있지만 스레드 카운터를 사용하는 세마포어의 경우 여러 스레드가 동시에 리소스에 액세스할 수 있다는 것입니다. 이것은 단순한 우연이 아닙니다 :) 뮤텍스는 실제로 세마포어입니다즉, 단일 스레드를 수용할 수 있는 세마포어입니다. 카운터가 1("잠금 해제됨")과 0("잠금됨")의 2개 값만 가질 수 있기 때문에 "바이너리 세마포어"라고도 합니다. 그게 다야! 보시다시피, 결국 그렇게 혼란스럽지 않습니다 :) 이제 인터넷에서 멀티스레딩을 더 자세히 공부하고 싶다면 이러한 개념을 탐색하는 것이 조금 더 쉬울 것입니다. 다음 수업에서 만나요!
코멘트
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION