큐의 요소 수가 0인지 판단할 때 take() 메서드가 if 대신 while 루프를 사용하는 이유는 무엇인가요?
으아악
깨어나는 이유도 put() 메소드가 새로운 요소를 넣는데 다른 스레드는 잠금을 얻을 수 없기 때문에 당연히 요소를 빼앗을 수 없기 때문입니다. 따라서 이때 잠금을 얻은 스레드의 경우 count는 확실히 0이 아닙니다. 요소를 얻으려면 dequeue()를 자유롭게 실행해야 합니다.
작성자가 while을 사용하여 무엇을 의미하는지 모르겠습니다.
"notEmpty.await() 메서드가 깨어나서 반환되므로 이 스레드는 잠금을 획득한 것이 틀림없습니다." 이 문장은 정확합니다.
당신이 작성한 코드가 다음과 같다고 가정해보세요:
으아악한 가지 분명한 점은
return dequeue()
之前需要满足的一个条件是count != 0
。我们假设 线程A 此时拿到了 lock,那么 线程A 的notEmpty.await()
此时便会停止阻塞,准备向下执行return dequeue()
。但是假设在竞争激烈的条件下,线程A 拿到 lock 之后,准备执行下一条 JVM 指令的时候,线程B 此时抢占了 lock,然后继续向下执行return dequeue()
,刚好使得 count 变为了 0;而此时因为写的只是if(count == 0)
,那么线程 A 在拿到 lock 之后,还是会继续向下执行return dequeue()
에 있는지 확인해야 하며 이로 인해 오류가 발생한다는 것입니다.왜
wait()
、await()
조건이 충족되지 않을 때 차단하는 방법을 while 루프에서 사용해야 하는 이유는 "Effective Java" 제2판 69조(244페이지)를 참조하세요.으아아아
따라서 코드에서 현재 대기열이 비어 있으면(개수==0) 호출
전에 제거 메소드를 실행하기 위해 스레드를 삽입하는 것이 가능할 수도 있습니다.notEmpty.await()
,这段代码对锁是有影响的,实际上底层上已经释放了锁,只是这个方法保证了被唤醒时一定又能够拿回锁(当有元素放入队列会调用notEmpty.signal()
进行唤醒),那为什么需要使用while呢?因为insert后lock.unlock
,未必notEmpty.await()
이 즉시 활성화됩니다.