026 Monitor

강의 메모 - Monitor - 모니터 -1,2 #

개요 #

  • 자바가 동기화를 지원하기 위해 사용하는 메커니즘은 모니터(Monitor) 이며 뮤텍스나 세마포어보다 더 고수준의 동기화 기법이다
    • 뮤텍스, 세마포어를 좀더 추상화한것
  • 모든 자바 객체는 기본적으로 모니터를 가지며 여러 스레드가 객체의 임계 영역(critical section)에 진입하려고 할 때 JVM 은 모니터를 사용하여 스레드 간 동기화를 제공한다
  • 자바의 모니터는 상호 배제(Mutual Exclusion) 및 협력(Cooperation)이라는 두 가지 동기화 기능을 제공하고 있으며 이를 위해 뮤텍스와 조건변수(Condition Variable)를 사용한다

상호배제 (Mutual Exclusion) #

  • 객체가 가지고 있는 모니터 Lock 을 통해 여러 스레드가 동시에 공유 자원에 접근하는 것을 막아 데이터의 일관성과 안전성을 보장하는 메커니즘이다
  • JVM 은 ‘synchronized’ 키워드를 이용하여 뮤텍스 동기화를 암묵적으로 처리해 주고 있으며 synchronized 는 메서드나 코드 블록에 적용할 수 있다.
    • 내부적으로 보이지않게 처리
    • synchrnozied 키워드 안에서 내부적으로 처리하는것
  • synchronized (동기화)
    • synchronized 블록은 해당 객체의 모니터를 획득 할 수 있으며 모니터를 획득한 스레드만이 임계영역에 접근 가능하고 그 외 다른 스레드들은 차단되어 대기 상태가 된다
    • synchronized 블록을 빠져 나오면 모니터 Lock 이 해제되고 대기 중인 다른 스레드 중 하나가 락을 얻고 임계 영역에 진입하여 작업을 수행하는 식으로 상호배제가 보장된다

협력 (Cooperation) #

  • 협력은 모니터의 Condition Variable (조건 변수) 를 통해 스레드 간 공동의 목표를 위해 상호협력으로 데이터의 일관성과 안전성을 보장하는 동기화 메커니즘이다
  • Condition Variable (조건변수)
    • 조건변수는 Object 클래스의 메소드인 wait(), notify(), notifyAll()과 함께 작용하며 특정 조건이 만족될 때까지 스레드를 대기시키는 기능을 제공한다
    • 스레드가 특정 조건에 부합하지 않을 때 wait() 메소드를 호출하면 조건변수의 대기 셋(Wait Set)에 들어가 대기한다
    • 다른 스레드가 특정 조건을 만족해서 notify() 또는 notifyAll() 메소드를 호출하면 해당 조건변수의 대기셋으로부터 스레드들을 깨워 실행시키게 된다.
  • 조건변수를 통해 스레드 간 대기와 통지를 서로 조절하면서 경쟁 조건(race condition)과 같은 문제를 방지할 수 있다.
  • 모니터 내부에는 여러개의 조건 변수를 가질 수 있지만 자바의 모니터에는 오직 한 개의 조건 변수만 가질 수 있다
    • t1이 대기하고있고, t2가 t1을 notify 할때의 실행영역의 조건 변수가 있고, 다른 t3은 조건변수가 또 있겠고, 조건 변수가 많아져서 선택될수록 구분해서 사용할 수 있겠지만, 모니터에는 1개의 조건 변수의 대기 큐에 다 들어가게된다. 그래서 일단 모든 쓰레드를 깨우고 실행영역을 수행하는 쓰레드가 있다.

모니터 대기 세트 구조 #

  • 자바의 모니터 내부에는 EntrySet(진입셋) 과 WaitSet(대기셋) 이라는 대기 자료 구조가 있으며 이들은 멀티스레드 환경에서 스레드들 간의 상호작용을 조절하는 데 사용된다

  • Entry Set

    • Entry Set 은 모니터의 Lock 을 획득하기 위해 대기 중인 스레드들을 모아 놓은 자료 구조로서 스레드가 Lock 을 사용 중인 경우 그외 다른 스레드는 Entry Set 에 들어가게 된다
    • Entry Set 에 있는 스레드들은 Lock 이 반납될 때까지 기다리며 락이 반납되면 Entry Set 중 하나의 스레드가 락을 획득하고 임계 영역으로 진입하게 된다
  • Wait Set

    • Wait Set 은 모니터의 조건 변수(Condition variable)와 함께 사용하는 자료구조이며 스레드들이 특정한 조건이 만족할 때 까지 대기하고 있는 장소이다
    • 스레드는 Wait Set 에 들어가 대기할 때 Lock 을 해제한다. 그리고 다른 스레드에 의해 깨어나게 되면 Entry Set 으로 이동해서 다시 Lock 을 획득 할 수 있다
    • 누군가가 깨워줘야한다. img.png

조건 변수 종류 #

  • 조건변수를 통해 상호 협력하고 있는 두 스레드가 wait() 과 notify() 메서드 실행 후에 하나의 모니터를 두고 두 스레드 모두 소유가 가능한 상황이 발생한다
  • 하나는 대기중인 스레드, 하나는 깨우는 스레드로서 어떤 스레드가 모니터를 먼저 소유할 것인가에 따라 두 종류의 조건변수로 나눌 수 있는데 Signal and Wait 와 Signal and Continue 이다

Signal and Wait #

  • 현재 모니터를 소유하고 있는 스레드가 wait() 을 실행하면 모니터 내부에서 자신을 일시 중단하고 Lock 을 해제한 후 Wait Set 에 들어간다
  • 깨우는 스레드가 notify() or notifyAll() 명령을 실행하면 Wait Set 에 있는 대기 스레드 중 하나 또는 모든 스레드를 깨우고 깨우는 스레드는 Lock 을 해제하고 대기한다
  • 대기에서 깨어난 스레드가 Lock 을 획득한 후 모든 작업을 마치고 Lock 을 해제하면 깨운 스레드가 Lock 을 획득한 후 계속 작업을 진행한다
  • 대기 스레드와 깨운 스레드 사이에 다른 스레드가 모니터를 소유할 수 없도록 원자적 실행이 보장되어야 한다
    • 깨운 스레드가 락을 반납하고 대기하고있고, 대기 스레드가 수행 이후 깨운 스레드가 다시 락을 얻는다. 이 사이에 락을 다른 스레드가 가져갈 수 없다는것

Signal and Continue #

  • 현재 모니터를 소유하고 있는 스레드가 wait() 을 실행하면 모니터 내부에서 자신을 일시 중단하고 Lock 을 해제한 후 Wait Set 에 들어간다
  • 깨우는 스레드가 notify() or notifyAll() 명령을 실행하면 Wait Set 에 있는 대기 스레드 중 하나 또는 모든 스레드를 깨운다. 이때 일어난 스레드들은 Entry Set 으로 이동한다
  • 깨우는 스레드는 Lock 을 계속 유지하면서 모든 작업을 완료하고 Lock 을 해제하면 Entry Set 에 대기하고 있는 모든 스레드가 Lock 을 획득하기 위해 경쟁한다
  • 자바에서는 이 조건 변수 형식을 취하고있다

자바 모니터 동작 구조 #

  1. 스레드가 모니터 영역에 진입하기 위해 synchronized 메서드를 호출하면 모니터가 작동한다
  2. 스레드는 모니터 영역 진입을 위해 Entry Set 에 입장해서 모니터 Lock 을 획득하기 위해 시도한다
  3. Entry Set 에서 이미 대기하고 있거나 현재 모니터를 소유한 스레드가 없으면 즉시 모니터의 소유자 되어 모니터 영역에 진입한다
  4. 만약 다른 스레드가 이미 모니터를 소유한 상태이면 모니터 영역에 진입하지 못하고 Entry Set 으로 들어가 대기한다
  5. Wait Set 에서 대기하는 스레드는 모니터 스레드가 모니터를 해제할 때 까지 계속 대기 상태를 유지한다
  6. 모니터 스레드가 모니터를 해제할 수 있는 경우는 두 가지인데 실행 중인 모니터 영역을 완료하거나 wait 명령을 실행하는 것이다 (해당 스레드는 lock을 갖고있겠다)
  7. 모니터 스레드가 어떤 조건에 부합하지 않아서 wait() 를 실행하면 모니터가 해제되고 Wait Set 에 들어가 대기한다 (락 반납)
  8. 이 때 다른 스레드가 모니터를 소유한 상태에서 만약 notify 를 실행하지 않고 그냥 종료하는 경우 Wait Set 의 스레드가 깨어나지 않기 때문에 Entry Set 의 스레드만 모니터를 두고 경쟁하게 된다
  9. 만약 모니터 스레드가 notify 를 실행하게 되면 Wait Set 에서 대기하고 있는 모든 스레드를 깨운다
  10. 깨어난 스레드는 모두 Entry Set 으로 이동하게 된다. 하지만 스레드가 깨어나는 즉시 모니터를 소유하는 것이 아니다
  11. 모니터 스레드는 모니터를 계속 소유한 상태에서 모니터 영역을 실행하고 종료한다
  12. 이 때 Entry Set 과 Wait Set 에서 이동한 모든 스레드가 모니터를 두고 경쟁하게 되는데 만약 조건 변수 대기에서 깨어난 스레드 중에서 모니터를 소유했는데 그 시점에 또 조건이 맞지 않으면 다시 wait 를 실행하고 대기 상태로 들어갈 수 있다
  13. Entry Set 과 Wait Set 에서 다음 스레드를 선택하는 기준은 오직 스케줄러에 의해 결정된다

모니터 구현 #

img_1.png ※ 일반적으로 모니터는 조건 변수를 여러개 가질 수 있으나 자바에서는 모니터당 오직 한개의 조건 변수를 가질 수 있다 (Lock 동기화 클래스에서 이 부분을 개선함)