변수의 기록

(CS) 모니터(Monitor)란? (컴퓨터 모니터 아님.) synchronized 본문

CS지식/운영체제 (Operating System)

(CS) 모니터(Monitor)란? (컴퓨터 모니터 아님.) synchronized

불광동 물주먹 2025. 4. 11. 00:08

1. 모니터(Monitor)란?

  • 정의: 모니터는 **상호배제(Mutual Exclusion)**와 **조건 동기화(Conditional Synchronization)**를 제공하는 고수준 동기화 추상화.
  • 주요 구성 요소:
    • 뮤텍스 락(Mutex Lock): 임계 구역(Critical Section)에 동시에 하나의 스레드만 들어갈 수 있도록 함.
    • 엔트리 큐(Entry Queue): 락을 얻기 위해 대기 중인 스레드들이 대기.
    • 컨디션 변수(Condition Variable): 특정 조건을 기다리는 스레드들이 대기하는 공간.
      • 웨이팅 큐(Waiting Queue): 컨디션 변수를 통해 조건을 기다리는 스레드들이 들어감.

이미지 출처 - 유튜브 쉬운코드

 

상황 1 -  producer 에서 item을 넣어주고 consumer에서는 꺼내 씀

조건 - 1. buffer 사이즈는 고정

문제점 1. producer 는 buffer에 빈공간이 없어도 계속 확인을 하고 넣어줘야하나?

문제점 2. consumer 에서도 buffer에 빈공간인데 계속 확인을 해가며 꺼내와야하나?

 

*위 문제를 모니터를 통해 해결 할 수 있다.

 

 

 

조건 1. global Buffer를 두고 공유
조건 2. Buffer 를 사용할때는 Critical Section 안에서 Mutual Exclusion이 보장 될 수 있도록 사용되어야한다.

     (보장하지 않으면 레이스 컨디션 발생 가능)
조건 3. global lock 은 뮤텍스 락 (lock 점유 실패시 엔트리 큐에 대기)


상황 1.프로듀서에서 item 삽입하려는데 -> 버퍼가 다 차면 웨이팅 (  웨이팅 큐 )  -> 작업을 완료한 컨슈머가 깨워줌( 대기 중인 한 쓰레드 웨이팅 큐 탈출)  ++ 깨우는 방법은 시그널이나 브로드캐스트로  -> lock 반환(엔트리큐 다음 쓰레드 진행 (순서는 개발자가 만들기 나름))

상황 2. 반대로 컨슈머에서 item 꺼내려는데 -> 버퍼가  비면 웨이팅(  웨이팅 큐 )   -> 작업을 완료한 프로듀서에서 버퍼 채운후 깨워줌 (대기 중인 한 쓰레드 웨이팅 큐 탈출) -> lock 반환(엔트리큐 다음 쓰레드 진행 (순서는 개발자가 만들기 나름))

상황 3. 작업이 끝나면 lock.relesase()로 뮤텍스 락 반환

 

**컨슈머 혹은 프로듀서 깨운 후 작업 진행 방법 2가지

1) signal & continue : 작업을 완료한 컨슈머가 꺠워준 후 작업 이어서 마저 한후 lock 반환

2) signal & wait :  작업을 완료한 컨슈머가 꺠워준 후 깨운 쓰레드가 작업 새로 시작하고 작업 마친 후 이후 락 반환 후 컨슈머 작업 재개  (컨슈머 작업 재개는 엔트리락에서 대기 후 자기 차례가 오면 진행)

 

*wait문은 반드시 while 문 안에서 실행되어야한다. (내가 기다렸던 조건이 충족되는지 다시 확인해야함!!)

 

 

 

2. Java에서의 모니터 구현

  • 모든 Object는 내부적으로 모니터를 갖는다.
    • synchronized 블록/메서드: 락 + 모니터 기능
    • 단일 컨디션 변수 제공 (wait, notify, notifyAll)

📌 synchronized 키워드 ( Mutual Exclusion  보장)

  • 객체의 모니터 락을 획득해야 진입 가능.
  • 락을 못 얻은 스레드는 엔트리 큐에서 대기.

📌 wait(), notify(), notifyAll()

  • wait(): 현재 스레드는 웨이팅 큐로 이동하여 대기 (락을 반납함).
  • notify(): 웨이팅 큐에서 하나의 스레드를 깨움.
  • notifyAll(): 웨이팅 큐에 있는 모든 스레드를 깨움.

⚠️ 반드시 wait/notify는 synchronized 블록 내부에서 호출되어야 함.

#java
synchronized(obj) {
     while (조건 안맞음) { 
         obj.wait();
      } 
      // 조건 맞음 - 작업 수행 
}

 

 

3. 여러 개의 조건 변수 필요 시 (Java 기준)

  • java.util.concurrent.locks.Condition 사용
  • ReentrantLock과 함께 사용
  • 하나의 Lock 객체에 여러 Condition 객체 생성 가능 (자바 기본 모니터와 차이점)

📌 예시 코드:

#java


Lock lock = new ReentrantLock();
Condition condA = lock.newCondition();
Condition condB = lock.newCondition();


lock.lock();
try {
         while (!조건A) {
               condA.await(); // wait
          } // 작업 수행
          condB.signal(); // 특정 조건에 대해 신호
} finally {
          lock.unlock();
}

 

 


4. 자바 동기화 관련 주요 클래스 (java.util.concurrent)

 

분류 클래스 설명
ReentrantLock 재진입 가능한 락, synchronized 대체
ReadWriteLock 읽기/쓰기 락 분리
StampedLock 낙관적 읽기 지원 (성능 개선)
조건 변수 Condition ReentrantLock과 함께 사용, 복수 조건 관리
동기화 큐 BlockingQueue, LinkedBlockingQueue Producer-Consumer 패턴에 사용
동기화 도구 Semaphore 지정된 수만큼의 동시 접근 허용
동기화 도구 CountDownLatch 특정 이벤트가 끝날 때까지 대기
동기화 도구 CyclicBarrier 지정된 수의 스레드가 모두 도달할 때까지 대기
동기화 도구 Phaser 단계적으로 동기화, CyclicBarrier 개선판
동기 변수 AtomicInteger, AtomicBoolean 원자성 보장 변수들 (CAS 기반)

정리 요약

  • 모니터 = 락 + 컨디션 변수
  • Java의 synchronized는 하나의 기본 컨디션 변수 내장 (wait/notify)
  • 여러 컨디션 필요 → ReentrantLock + Condition
  • wait()는 항상 while로 조건을 확인해야 함 (스퍼리어스 웨이크업 방지)
  • 고성능, 유연한 동기화 → java.util.concurrent 사용 권장