이 내용은 "Java 언어로 배우는 디자인 패턴 입문 - 멀티쓰레드편" 책의 Introduction 01 부분을 정리한 것이다.
쓰레드의 일시 정지 (sleep)
public class Main { public static void main(String[] args) { for (int i = 0; i < 10; i++) { System.out.print("Good!"); try { // sleep() 메소드는 InterruptedException을 발생시킬 수 있음 Thread.sleep(1000); // 1000밀리초=1초동안 현재의 쓰레드를 일시정지함 } catch (InterruptedException e) { } } } }
"Good!"을 출력한 뒤, sleep() 메소드 호출로 인하여 해당 쓰레드가 1초(1000밀리초) 동안 일시정지 된다.
1초가 지난 뒤에는 스스로 깨어나서, 수행하던 코드를 마저 수행한다.
따라서 1초 간격으로 "Good!"이 출력되게 된다.
참고사항
- Thread.sleep으로 잠들어 있는 쓰레드를 도중에 깨우려면 interrupt를 발생시켜야 한다.
- public static void sleep(long millis) throws InterruptedException
- public static void sleep(long millis, int nanos) throws InterruptedException
- 밀리초 뿐 아니라 나노초도 지정 가능하다. 하지만 실질적으로 그렇게까지 세세한 제어는 되지 않는다.
쓰레드의 대기 (wait)
모든 인스턴스들은 각각 wait 집합을 가지고 있다. wait() 메소드를 실행한 후 대기중인 쓰레드들의 (가상의, 개념적인) 집합이다.
wait(); // 이 둘은 동일함
this.wait();
락을 획득하여 실행되고 있던 쓰레드가 wait() 메소드를 만나면 동작을 정지하고, wait 집합에 들어가고, 가지고 있던 락을 해제한다.
(바꿔 말하자면, 락을 가지고 있는 쓰레드만 wait() 메소드를 실행할 수 있다.)
그리고 다음 중 어느 한 상황이 발생하기 전까지는 영원히 wait 집합 안에서 잠들어 있는다.
- 다른 쓰레드의 notify() 메소드 호출에 의해 깨어난다.
- 다른 쓰레드의 notifyAll() 메소드 호출에 의해 깨어난다.
- 다른 쓰레드의 interrupt() 메소드 호출에 의해 깨어난다.
- wait() 메소드가 타임아웃 된다.
대기 중인 쓰레드 한 개 깨우기 (notify)
락을 획득하여 실행되고 있던 쓰레드가 notify() 메소드를 호출하면, 해당 인스턴스의 wait 집합에 있는 쓰레드 한 개가 wait 집합에서 꺼내진다. 이 때 wait 집합 안에 있는 쓰레드 중 어떤 쓰레드가 선택될지는 정해져 있지 않다.
(wait와 마찬가지로, 락을 가지고 있는 쓰레드만 notify() 메소드를 호출할 수 있다.)
인스턴스명.notify();
notify() 호출에 의하여 wait 집합에서 나온 쓰레드가 곧바로 실행을 재개하는 것은 아니다. 실행을 재개하려면 wait 집합에 들어갈 때 해제했던 락을 다시 획득해야 하는데.. notify()가 호출된 순간에는 notify()를 실행한 쓰레드가 해당 락을 가지고 있는 상태이기 때문이다.
대기 중인 모든 쓰레드 깨우기 (notifyAll)
notifyAll(); // this.notifyAll()과 동일함
this.notifyAll(); // notifyAll()과 동일함
인스턴스명.notifyAll();
락을 획득하여 실행되고 있던 쓰레드가 notifyAll() 메소드를 호출하면, 해당 인스턴스의 wait 집합에 있는 모든 쓰레드를 wait 집합에서 꺼낸다.
(wait, notify와 마찬가지로, 락을 가지고 있는 쓰레드만 nodifyAll() 메소드를 호출할 수 있다.)
wait() & notify() & notifyAll()
1.
위에서도 언급했듯이 wait, notify, notifyAll 메소드는 전부 '락을 가지고 있던 쓰레드'만이 호출할 수 있다.
락을 가지고 있지 않은 쓰레드가 wait(), notify(), notifyAll() 메소드를 호출할 경우는 java.lang.IlegalMonitorStateException이 발생한다.
2.
wait, notify, notifyAll 메소드는 java.lang.Object 클래스의 메소드이지 Thread 클래스의 메소드가 아니다.
이 세개의 메소드는 쓰레드에 대한 조작이라고 하기 보다는, 인스턴스의 wait 집합에 대한 조작이다. wait 집합은 모든 인스턴스가 가지고 있으므로 wait, notify, notifyAll은 Object 클래스의 메소드인 것이다.
(Object 클래스는 모든 클래스의 슈퍼클래스이므로, 엄밀히 말하자면 Thread 클래스의 (슈퍼클래스의) 메소드이다.)
댓글