Java

SCJP 80번 문제 / synchronized

bang2001 2013. 7. 25. 16:46

QUESTION 80

Given:
7. void waitForSignal() {
8. Object obj = new Object();
9. synchronized (Thread.currentThread()) {
10. obj.wait();
11. obj.notify();
12. }
13. }

Which statement is true?

A. This code can throw an InterruptedException.
B. This code can throw an IllegalMonitorStateException.
C. This code can throw a TimeoutException after ten minutes.
D. Reversing the order of obj.wait() and obj.notify() might cause this method to complete normally.
E. A call to notify() or notifyAll() from another thread might cause this method to complete normally.
F. This code does NOT compile unless "obj.wait()" is replaced with "((Thread) obj).wait()".

Answer: B

-------------------------------------------------------------------------------------------

다음 문제에 대해서 해석해 보면 다음과 같다.

"다음 코드에 대한 상태로 옳은것은?"

먼저 위의 코드를 해석해 보겠다.

7번째 라인에서는 메소드를 선언하였고,
8번째 라인에서는 Object 타입의 obj라는 참조변수를 선언하여 이 변수에
Object객체를 생성하여 참조값을 가지도록 하였다.

9번째 라인을 보면 synchronized(){} 을 볼 수 있는데 이 synchronized
우리가 수업시간에 배운 synchronized 와 역할은 똑같으나 적용범위가 약간 틀리다.

 - public synchronized void 메소드명() : 특정 메소드에 대해서 동기화 처리
 - synchronized(//동기화 하고자 하는 객체 or 클래스명){//동기화시킬 코드}
   : 특정 블럭에 대해서 동기화 처리를 한다. 보통 인스턴스 메소드 내에서 특정 블럭에
     동기화 처리를 할 경우에는 synchronized()의 매개변수로 객체를 넣고(보통 this 를 넣는다.),
static 메소드의 경우에는 this로 접근이 안되므로 클래스명이 들어간다.(문자열로 클래스파일명이나 클래스이름을 넣는다.)

위와 같이 적용이 된다. 여기서는 후자의 방법으로 적용이 된 것이다.
즉 9번라인부터 12번 라인까지 동기화가 적용된 것이다.

동기화란 멀티스레드에서 하나의 스레드가 먼저 자원을 점유한 경우에 다른 스레드는 이 자원을 점유하기 위해서
대기상태로 들어가고, 먼저 자원을 쓰고있던 스레드가 작업을 마치고 자원에 대한 소유권을 놓게 되면
대기중인 스레드가 이 자원을 점유하는것이라고 보면 된다. 

다시말하면 스레드에 락을 걸어서 스레드의 동작을 일시적으로 멈추게 하는 것이다.
그런데 위의 코드를 보면, 처음 스레드가 동기화 블럭이 처리된 코드를 점유하게 되면
다른 스레드는 이 자원에 대해서 점유할 수 없게 된다.(대기상태로 들어가게 된다.)

그런데 처음 동기화된 코드를 점유한 스레드의 내부에서 10번째 라인에서
wait()메소드(싱글스레드를 기준으로 스레드의 동작을 대기상태로 설정한다. 즉 스레드가 일시적으로 멈춘다.)
를 사용하면 동기화된 코드를 점유한 상태에서 스레드가 일시적으로 멈추게 된다.

다시말하면 80번 문제의 코드는 하나의 스레드가 동기화된 코드를 독점하게 되는 것이다.
따라서 실행 할 때 JVM에서 예외를 발생시키게 되는 것이다.
 
하나의 동기화된 객체는 현재 실행되고 있는 스레드(문제에서 작성된 소스코드가 포함된 객체를 실행하는 스레드를 말한다.)
객체를 동기화 대상으로 지정하였고, 이 스레드에 wait() 메소드를 사용하여 스레드를 일시적으로 정지 시켰다.
이렇게 되면 이 스레드가 정지된 상태이기 때문에 하단의 notify() 메소드를 실행할 수 없다.

즉, 설사 11번째 라인에서 notify() 메소드를 통해서 대기중인 스레드를 다시 시작하는 코드로
구성하였더라도 JVM에서 실행 할 때 10번째 라인에서 예외가 발생하기 때문에 이때 스레드에
Interrupt가 걸리게 되고 따라서 11번째 라인은 수행하지 못하게 되는 것이다.

따라서 답은 B번 이다.

※ IllegalMonitorStateException 예외
   - 위의 예외는 스레드가 락을 부정적으로 점유하였을 때 발생하는 예외이다.
     Illega(불법적인) Monitor(모니터?) State(상태) Exception(예외)
 
여기서 말하는 Monitor 란 하나의 스레드가 동기화된 블럭을 점유하고 있을때의 상황을 
표현하기를 "스레드가 모니터를 가지고 있다" 라고 표현한다. 즉 스레드가 
동기화된 자원에 대한 점유를 말한 것이다.