Why the take() method uses a while loop instead of if when judging whether the number of elements in the queue is 0;
我认为,如果notEmpty.await()方法既然苏醒返回了 ,那么此线程肯定拿到了lock。
The reason for waking up is also because the put() method puts in new elements, and other threads cannot get the lock, so naturally they cannot take away the elements. So at this time, for the thread that got the lock, the count is definitely not 0. , you should feel free to execute dequeue() to obtain the elements.
I don’t know what the author means by using while?
"Since the notEmpty.await() method wakes up and returns, then this thread must have obtained the lock" This sentence is correct.
Suppose the code you write is:
One thing that is clear is that we need to ensure that it is in
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()
, which leads to the error.As to why
wait()
、await()
this method of blocking when the conditions are not met must be used in a while loop, you can refer to Article 69 (page 244) of the second edition of "Effective Java".So when the current queue in your code is empty (count == 0), the call
notEmpty.await()
,这段代码对锁是有影响的,实际上底层上已经释放了锁,只是这个方法保证了被唤醒时一定又能够拿回锁(当有元素放入队列会调用notEmpty.signal()
进行唤醒),那为什么需要使用while呢?因为insert后lock.unlock
,未必notEmpty.await()
will wake you up immediately. You may insert a thread to run the remove method before