모니터란?
개념
- mutual exclusion 보장
- 조건 따라 스레드 대기 상태 전환 기능 제공
언제 사용되나?
- 한번에 하나의 스레드만 실행해야 할 때
- 여러 스레드와 협업 필요할 때
구성요소 (M + CV)
![](https://velog.velcdn.com/images/onetuks/post/4fc6757b-cb0e-4a38-af0c-e2cf50ebb14e/image.png)
Mutex
- critical section 내
mutual exclusion 보장
위한 장치
critical section
진입 위해 mutext lock
필요
mutex lock
취득 못한 스레드는 entry queue
에 들어간 후 waiting 상태로 전환
- Mutex 락을 쥔 스레드가 락을 반환하면 락을 기다리며 큐에 대기상태로 있던 스레드 중 하나가 실행
Entry queue
(critical section 진입 관련 큐)과 관련
Condition Variable
Waiting Queue
가짐
- 조건이 충족되길 기다리는 스레드들이 대기 상태로 머무는 곳
Condition Variable 주요동작
동작 | 설명 |
---|
wait | 스레드가 자신을 CV 내 WaitingQ 에 넣음 |
signal | WaitingQ 내 대기 스레드 하나 깨움 |
broadcast | WaitingQ 내 대기 스레드 전부 깨움 |
두 개의 큐
종류 | 설명 |
---|
Entry Queue | Critical Section 진입 대기 큐 |
Waiting Queue | 조건 충족 대기 큐 |
Bounded P/C problem
![](https://velog.velcdn.com/images/onetuks/post/fd3f09df-1085-46a1-bc58-f77439d6f745/image.png)
- Producer 는 buffer 가 찼는지 계속 확인해야 함
- Consumer 는 buffer 에 아이템이 있는 계속 확인해야 함
- 모니터 활용해 해결 가능
- CV 조건 확인 구문은 반드시 while 문 안에 배치
- 락 획득 후 조건 확인 위해
while (q.isEmpty()) {
wait(lock, emptyCV);
}
![](https://velog.velcdn.com/images/onetuks/post/d8a9ee80-45cc-4f90-a886-490d15f6e42e/image.png)
Java 모니터
모든 객체 내부적 모니터 존재
synchronized
키워드로 모니터 mutual exclusion
기능
- 자바 모니터는
CV 하나만
- 여러개가 필요한 경우 따로 설정하면 됨
- 세 가지 동작
- wait
- notify
- notifyAll
(broadcast)
- java.util.concurrent 에 동기화 클래스
class BoundedBuffer {
private static final int SIZE = 5;
private final int[] buffer = new int[SIZE];
private int count = 0;
public synchronized void produce(int item) {
while(count == 5) {
wait();
}
buffer[count ++] = item;
notifyAll();
}
public void consume() {
int item = 0;
synchronized (this) {
while (count == 0) {
wait();
}
item = buffer[-- count];
notifyAll();
}
System.out.println("Consume: " + item);
}
}
public class Main {
public static void main(String[] args) throws {
BoundedBuffer buffer = new BoundedBuffer();
Thread consumer = new Thread(() -> buffer.consume());
Thread producer = new Thread(() -> buffer.produce());
consumer.start();
producer.start();
consumer.join();
producer.join();
}
}