반응형
모니터
세마포어나 뮤텍스를 잘못 사용해서 일어나는 에러가 발생할 수 있다.
따라서 자바에서는 더욱 심플한 동기화 툴인 "모니터"를 제공한다.
- 고급 언어의 설계 구조물로서, 개발자의 코드를 상호배제 하게끔 만든 추상화된 데이터 형태이다.
- 공유자원에 접근하기 위한 키 획득과 자원 사용 후 해제를 모두 처리한다. (세마포어는 직접 키 해제와 공유자원 접근 처리가 필요하다.
- 모니터의 개념
- 하나의 데이터(객체)마다 하나의 모니터를 결합할 수 있으며, 모니터는 그것이 결합된 데이터(객체)가 동시에 두 개 이상의 스레드에 의해 접근할 수 없도록 막는 잠금(lock)기능을 제공함으로써, 동기화를 수행하는 동기화 도구이다.
- 즉, 데이터(객체)에 모니터를 결합하면 하나의 스레드가 그 데이터를 사용하는 동안에는 다른 스레드들이 그 데이터를 사용할 수 없게 된다.
- 자바에서는
synchronized
메소드가 선언된 객체와synchronized
블럭에 의해 동기화 되는 모든 객체에 고유한 모니터가 결합이 되어 동기화 작업을 수행한다.
- 모니터의 구성
- 스레드 단위로 모니터락을 획득(
acquire lock
)하거나 반환(release lock
)한다. - 동기화 코드(동기화메소드나 블럭)을 수행할 때에는 동기화 대상 인스턴스와 결합된
Monitor Lock
을 획득한 후에 집입이 가능하며, 동기화 코드를 벗어날 때에는Monitor Lock
을 반환한다. - 동기화 댕상 인스턴스 별로 이와 결합된 Monitor가 존재하며 해당 모니터는 현재 락을 획득한 스레드와 Lock Count 정보를 관리한다.
- 모니터가 Lock Count정보를 유지한다는 것은 동일 스레드가 중복해서 lcok을 걸 수 있다는 의미이다.
- 상호배제 임계영역 구현
모니터 타입은 상호배제를 제공해주는
ADT
이다. 쉽게 말해서 클래스이다.- 여기서
ADT
란Abstract Data Type
으로 추상 자료형이다. - 객체지향의 클래스와 같이 기능의 구현 부분을 나타내지 않고, 데이터의 형태와 그 데이터의 연산들을 정의 해놓은 자료형이다.
- 우리가 알고 있는 자료구조(Data Structure)는 추상 자료형이 정의한 연산들을 구현한 구현체를 가리킨다.
- 즉, 추상 자료형은 구현 방법을 명시하고 있지 않다0는 점에서 자료구조와 다르다.
- 자바로 치면 클래스인지 인터페이스인지 확인하면 된다.
- 스택이나 큐는 구현 방법이 전혀 정의되어 있지 않으니
추상자료형
이고, 배열은 연속적으로 저장되어 있도록 구현되어 있어야 하므로자료구조
이며, 연결리스트도 다음 데이터의 위치를 저장하는 방식으로 정해져 있으니자료구조
이다.
- 여기서
synchronized block { // 임계영역에 해당하는 코드 블럭을 선언할 때 사용한다. // 해당 임계영역에는 모니터 락을 획득해야 진입할 수 있다. // 모니터 락을 가진 객체 인스턴스를 지정할 수 있다. // 메소드에 선언하면 메소크 블록 전체가 임계영역으로 지정된다. // 이 때 모니터락을 가진 객체 인스턴스는 this 객체 인스턴스이다. } synchronized (object) { // critical section }
지금 까지 어렵게 상호배제를 구현한 것을,
JAVA VM
은 위와 같이 심플하게 끝낼 수 있다.여기까지는 임계영역을 선언한 것이고 동기화는 되지 않은 것이다.
- 동기화 구현
- 동기화를 하기 위해선
wait()
와notify()
메소드가 필요하다. - 위 메소드는
java.lang.Object Class
에 선언 되었다 (이 말은 모든 자바 객체가 가진 메소드이다.) - 쓰레드가 어떤 객체의
wait()
메소드를 호출하면 해당 객체의 모니터락을 획득하기 위해 대기 상태로 진입한ㄷ. - 쓰레드가 어떤 객체의
notify()
메소드를 호출하면 해당 객체의 모니터에 대기중인 쓰레드 하나를 깨운다. notify()
대신notifyAll()
을 사용하면 해당 객체 모니터에 대기중인 모든 쓰레드를 깨운다.
static class Counter {
public static int count = 0;
synchronized public static void increment() {
// critical section
count++;
}
}
/* 이렇게 method 앞에 modifed로 선언하는 것이 현하긴 하지만 내가 정하고 싶은 블록만 동기화 하기 위해선 이렇게도 가능하다. */
private static Object object = new Object();
synchronized (object) {
count++;
}
/* 여기서 this는 자기 참조 변수 이기 때문에 각각의 쓰레드의 this를 참조 하는 것이다. */
/* -> 이 말은 모니터가 다 따로 존재한다는 의미로, 쓰레드 끼리 독립적이다. */
/* -> 이는 static으로 선언했기 때문에 ! */
synchronized (this) {
counter.count++;
}
/* 하나의 인스턴스를 생성하고, 이를 쓰레드의 인자로 넘겨주면 같은 Counter()라는 동기화 블록이 동기화 된다. */
Counter count = new Counter();
for (...) {
thread[i] = new Thread(new MyRunnable(counter));
thread[i].start();
}
지금까지 배운 mutex, semaphore, monitor
는 상호배제만 해결한 동기화 도구이다.
그래서 그러한 문제도 해결해보자고 최근에 나온것이 바로 Liveness
이다.
반응형
'Computer Science > [ OS ]' 카테고리의 다른 글
[ OS ] 10. 프로세스 동기화 - 전통적인 동기화 문제 (0) | 2021.05.31 |
---|---|
[ OS ] 09. 프로세스 동기화 - 우선순위 역전(Priority Inversion)과 상속(Inheritance) (0) | 2021.05.30 |
[ OS ] 07. 프로세스 동기화 - 임계영역문제의 해결책 ? Mutex, Semaphore ! (0) | 2021.05.30 |
[ OS ] 06. 프로세스 동기화 - 임계영역(Critical Section) (0) | 2021.05.30 |
[ OS ] 05. 동기와 비동기(Sync, Async) (0) | 2021.05.27 |