자바 wait()과 notify()에 대해서 알아보자.
synchronized로 동기화 해서 공유 데이터를 보호하는 것은 좋지만, 특정 쓰레드가 객체의 락을 가진 상태로 오랜 시간을 보내지 않도록 해야한다. 만일 계좌에 출금할 돈이 부족해 한 쓰레드가 락을 보유한 채로 돈이 입금될 때까지 계속 기다리면 다른 쓰레드 들은 해당 객체의 락을 기다리느라 다른 작업들이 원활하지 않을 것이다.
이러한 상황을 개선하기 위해 wait()과 notify()가 있다. 동기화된 임계 영역의 코드를 수행하다가 작업을 더 이상 진행할 상황이 아니면, wait()을 호출해 쓰레드가 락을 반납하고 기다리게 한다. 그러면 다른 쓰레드가 락을 얻어 해당 객체에 대한 작업을 수행할 수 있게 된다. 나중에 작업을 진행할 수 있는 상황이 오면 notify()를 호출해서 작업을 중단했던 쓰레드가 다시 락을 얻어 작업을 진행할 수 있다.
wait()이 호출되면, 실행 중이던 쓰레드는 해당 객체의 대기실(waiting pool)에서 통지를 기다린다. notify()가 호출되면, 해당 객체의 대기실에 있던 모든 쓰레드 중에서 임의의 쓰레드만 통지를 받는다. notifyAll()은 기다리고 있는 모든 쓰레드에게 통보를 하지만, lock을 얻을 수 있는 것은 임의의 하나의 쓰레드이다.
wait()은 지정된 시간동안만 기다린다. 지정된 시간이 지난 후에 자동적으로 notify()가 호출되는 것과 같다. 그리고 waiting pool은 객체마다 존재하는 것이므로 notifyAll()이 호출된다고 해서 모든 객체의 waiting pool에 있는 쓰레드가 깨워지는 것은 아닌다. notifyAll()이 호출된 객체의 waiting pool에 대기중인 쓰레드만 해당된다.
ex)
코드가 많이 길지만, 요리사가 테이블에 6개 미만이면 요리를 추가하고 notify()를 하며, 6개 이상이면 wait()을 한다. 손님은 각각 donut과 burger를 먹는 손님이 있으며, 원하는 음식과 일치하면 음식을 먹고 notify()를 하며, 음식이 없거나 원하는 음식이 없으면 wait()을 한다.
여기서 문제는 waiting pool이 같으므로, notify()를 했을 때 요리사를 호출해야하는데 요리사와 손님이 같이 대기하고 있을 경우에는 임의의 한명을 호출하기 때문에 손님이 또 호출될 수 있다는 것이다.
'언어공부 > Java' 카테고리의 다른 글
자바 예외 처리 방법 - try-catch문, printStackTrace()와 getMessage() (0) | 2021.06.03 |
---|---|
자바 프로그램 오류 및 Exception과 RuntimeException (0) | 2021.06.02 |
자바 쓰레드 동기화(synchronization) (0) | 2021.05.31 |
자바 쓰레드 스케쥴링 메소드-sleep(), interrupt(), suspend(), resume(), stop(), join(), yield() (0) | 2021.05.31 |
자바 쓰레드의 I/O 블락킹(blocking) (0) | 2021.05.31 |