Java의 "primitives"(synchronized, wait(), notify())를 사용하여 Java의 바운드 BlockingQueue 인터페이스와 유사한 것을 구현하려고했지만 이해가 안되는 동작을 발견했습니다.자바 : 대기 중 2 개 + 블로킹 된 1 개 스레드, notify()는 라이브 록으로 연결되며 notifyAll()은 그렇지 않습니다.
하나의 요소를 저장할 수있는 큐를 만들고 큐에서 값을 가져 오기 위해 대기하는 두 개의 스레드를 만들고 시작한 다음 주 스레드의 동기화 된 블록에있는 큐에 두 개의 값을 넣으려고합니다. 대부분의 경우 작동하지만 때로는 값을 기다리는 두 개의 스레드가 겉보기에는 서로 깨어나서 주 스레드가 동기화 된 블록에 들어 가지 않게하기 시작합니다.
가 여기 내 (간체) 코드입니다 :
import java.util.LinkedList;
import java.util.Queue;
public class LivelockDemo {
private static final int MANY_RUNS = 10000;
public static void main(String[] args) throws InterruptedException {
for (int i = 0; i < MANY_RUNS; i++) { // to increase the probability
final MyBoundedBlockingQueue ctr = new MyBoundedBlockingQueue(1);
Thread t1 = createObserver(ctr, i + ":1");
Thread t2 = createObserver(ctr, i + ":2");
t1.start();
t2.start();
System.out.println(i + ":0 ready to enter synchronized block");
synchronized (ctr) {
System.out.println(i + ":0 entered synchronized block");
ctr.addWhenHasSpace("hello");
ctr.addWhenHasSpace("world");
}
t1.join();
t2.join();
System.out.println();
}
}
public static class MyBoundedBlockingQueue {
private Queue<Object> lst = new LinkedList<Object>();;
private int limit;
private MyBoundedBlockingQueue(int limit) {
this.limit = limit;
}
public synchronized void addWhenHasSpace(Object obj) throws InterruptedException {
boolean printed = false;
while (lst.size() >= limit) {
printed = __heartbeat(':', printed);
notify();
wait();
}
lst.offer(obj);
notify();
}
// waits until something has been set and then returns it
public synchronized Object getWhenNotEmpty() throws InterruptedException {
boolean printed = false;
while (lst.isEmpty()) {
printed = __heartbeat('.', printed); // show progress
notify();
wait();
}
Object result = lst.poll();
notify();
return result;
}
// just to show progress of waiting threads in a reasonable manner
private static boolean __heartbeat(char c, boolean printed) {
long now = System.currentTimeMillis();
if (now % 1000 == 0) {
System.out.print(c);
printed = true;
} else if (printed) {
System.out.println();
printed = false;
}
return printed;
}
}
private static Thread createObserver(final MyBoundedBlockingQueue ctr,
final String name) {
return new Thread(new Runnable() {
@Override
public void run() {
try {
System.out.println(name + ": saw " + ctr.getWhenNotEmpty());
} catch (InterruptedException e) {
e.printStackTrace(System.err);
}
}
}, name);
}
}
가 여기에 내가 무엇을보고 때 그것은 "블록"그러나
(skipped a lot)
85:0 ready to enter synchronized block
85:0 entered synchronized block
85:2: saw hello
85:1: saw world
86:0 ready to enter synchronized block
86:0 entered synchronized block
86:2: saw hello
86:1: saw world
87:0 ready to enter synchronized block
............................................
..........................................................................
..................................................................................
(goes "forever")
, 나는() (그동안 내부에서 호출이 통지 변경하는 경우. ..) addWhenHasSpace 및 getWhenNotEmpty 메소드의 notifyAll() 루프는 "항상"통과합니다.
제 질문은이 경우입니다 :이 경우 notify()와 notifyAll() 메소드간에 동작이 다르며 notify()의 동작이 왜 그런가?
- 는이 경우의 notifyAll()는 일어나 것이라고 나에게 보인다 때문에
나는 (두 스레드가 하나가 BLOCKED 대기) 두 가지 방법이 경우에 같은 방식으로 행동 기대 다른 스레드는 notify()와 동일합니다.
- 스레드를 깨우는 방법의 선택에 따라 깨어나는 스레드 (예 : RUNNABLE 추측)와 기본 스레드 (차단 된 스레드)가 달라집니다. 나중에은 잠금을 위해 경쟁합니다. 내가 javadoc에서 기대할 수있는 것뿐만 아니라 주제에 관한 인터넷 검색.
어쩌면 내가 뭔가 잘못하고있는 것일까 요?
왜'notify()'*와 *'wait()'를 반복하여 호출합니까? 두 개의 모니터가 필요합니다. 하나는 "소비 할 항목이 있고"다른 하나는 "채워질 공간이 있습니다"입니다. –
고마워요, 당신은 내가 바보 같은 일을 끊임없이 일어나고있는 것을 깨닫게했습니다. 나는 문제에 집중하고 (명백한) 더 나은 방법을 보지 못했다. 아직도 notify()와 notifyAll()이이 경우 다르게 동작하는 이유는 무엇입니까?하지만 작동하는 훨씬 더 좋은 방법이 있으므로이 질문은 단지 이론적 인 흥미에 불과합니다. – starikoff