2016-11-22 3 views
1

알고 싶습니다. 예를 들어 r.wait()가 작동합니까? 이 코드 :notify/wait()를 사용하여 특정 (그룹) 스레드를 깨우거나 일시 중단 할 수 있습니까?

public class Buffer1<T> { 
private T content; 
private boolean empty; 
private Object r = new Object(); 
private Object w = new Object(); 

public Buffer1() { 
empty = true; } 

public Buffer1(T content) { 
this.content = content; 
empty = false; } 

public T take() throws InterruptedException { 
synchronized (r) { 
while (empty) { 
r.wait(); 
} 

synchronized (w) { 
empty = true; 
w.notify(); 
return content; 
    } 
} 
} 

public void put(T o) throws InterruptedException { 
synchronized(w) { 
while (!empty) { 
w.wait(); 
} 

synchronized (r) { 
empty = false; 
r.notify(); 
content = o; 
} 

방법 r.wait 않습니다(), r.notify w.wait는(),(), w.notify은() 일? 동기화 된 (r)/동기화 된 (w)과 함께 어떻게 작동합니까?

+0

글쎄, 당신의 인생은'notifyAll()'을 사용하면 더 간단 해 질 것이다 ... 특정 스레드 그룹을 깨우기로되어 있지 않다. 그것은 깨어납니다. 이것이'wait()'가 항상 루프 안에서 발생하는 이유입니다. 잠에서 깨어 나면 스레드 자체가 잠에서 깨어 나면 좋은 시간인지 확인하고 그렇지 않으면 다시 wait()로 돌아갑니다. 그러나 wake와 notify는 동시 프로그래밍을위한 저수준 구조이기 때문에 동시 모듈을 더 간단하게 만드는 Executor Framework를 사용해야합니다. – scottb

+0

또는'java.util.concurrent' 패키지의 세마포어. – EJP

답변

0

스레드가 그룹에서 일시 중지되지 않습니다. 스레드가 동기화 된 블록이나 메소드에 들어가서 잠금 (여기서는 r 또는 w)을 획득하고, 스레드가 획득 한 잠금을 가진 객체에서 스레드가 호출을 대기하면 스레드는 일시 중단되고 대기라고하는 잠금을 해제하고 해당 잠금에 대한 대기 세트에 추가됩니다.

대기 호출을 둘러싼 루프가있는 패턴이 여기에 있습니다. 메서드를 호출하는 스레드는 루프의 테스트가 false가 될 때까지 대기해야합니다. 쓰레드가 대기 상태가되는 상태를 조건이라고합니다. wait 메소드는 주로 통지 된 스레드가 잠금의 소유권을 가지지 않기 때문에 루프에서 호출됩니다. 잠금을 다시 획득하면 현재 상태를 테스트해야합니다.

잠금 대기 상태의 모든 스레드는 해당 잠금에 대해 notifyAll을 호출하여 깨울 수 있습니다. 일반적으로 스레드 중 하나만 잠금을 획득하고 한 번에 진행할 수 있기 때문에 실제로는 최적이 아닙니다. notifyAll 사용은 동일한 잠금을 위해 경합하는 스레드가 다른 조건을 기다릴 수 있고 일부 스레드와 관련이없는 상태에 대한 통지가있을 때 발생합니다. 알림이 사용되면 하나의 스레드 (스케줄러의 분위기에 따라 선택됨) 만 깨어납니다. 스레드가 대기중인 조건이 통지가없는 경우 알림은 손실되고 스레드는 진행하지 않습니다. 통지가 어느 thread에도 적용 가능한 경우는 notifyAll를 사용해, 그 중 한쪽이 진척 할 수 있습니다. 상황을 전환하고 대기 상태로 되돌아가는 대기중인 다른 모든 스레드를 희생 시키더라도 대안을 능가합니다.

게시 된 코드에서 각 조건에 대해 별도의 잠금 개체를 사용하여 notifyAll을 사용하지 않는 것이 좋습니다. 객체 r에는 버퍼가 비어 있지 않을 때까지 기다리는 쓰레드가 있고, 객체 w는 버퍼가 비워 질 때까지 쓰레드를 기다리고있다. 그렇게하면 notify가 호출되면 알림이 관련이있는 스레드를 깨울 수 있습니다 (넣으려는 스레드 만 w.notify()까지 깨울 수 있음).

이 코드의 문제점은 put 및 take 조작이 두 가지 잠금을 모두 확보하고 서로 반대 순서로 획득한다는 것입니다. 교착 상태를 일으키는 좋은 방법입니다. 동기화 된 키워드와 내장 된 잠금을 사용하면 타임 아웃 및 복원 할 수 없으므로 복구 할 수있는 좋은 방법이 없습니다. 한 스레드가 r을 갖고 w가 필요하고 다른 스레드가 w를 갖고 r을 원할 경우 케이스가 생기면 멈추게됩니다. 락을 보관 유지하는 2 개의 thread는 진척 할 수 없기 때문에, 다른 thread는 어느 쪽의 락도 취득 할 수 없기 때문에, JVM를 종료 할 때까지,이 thread의 메소드에 들어가는 모든 thread가 블록됩니다.