為什麼take()方法在判斷佇列中元素個數是否為0的時候使用了while循環,而不是if;
我认为,如果notEmpty.await()方法既然苏醒返回了 ,那么此线程肯定拿到了lock。
而甦醒的原因也是因為put()方法放入了新的元素,而其他線程無法拿到鎖,自然無法取走元素,那麼此時對於拿到鎖的線程來說count肯定不為0了,應該放心的執行dequeue()取得元素就可以了。 不知道作者使用了while是何意呢?
闭关修行中......
“notEmpty.await()方法既然甦醒返回了 ,那麼此線程肯定拿到了 lock” 這句話是正確的。
假設你寫的程式碼是:
if (count == 0) 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(),從而導致了錯誤。
return dequeue()
count != 0
notEmpty.await()
if(count == 0)
關於為什麼wait()、await() 這樣當條件不滿足時就阻塞的方法一定要在 while 循環中使用,可以參考《Effective Java》第二版第 69 條(244 頁)。
wait()
await()
public ArrayBlockingQueue(int capacity, boolean fair) { if (capacity <= 0) throw new IllegalArgumentException(); this.items = new Object[capacity]; lock = new ReentrantLock(fair); notEmpty = lock.newCondition(); //notEmpty 就是这个锁的条件 notFull = lock.newCondition(); }
所以在你這段程式碼裡目前隊列為空時(count==0),呼叫了notEmpty.await(),这段代码对锁是有影响的,实际上底层上已经释放了锁,只是这个方法保证了被唤醒时一定又能够拿回锁(当有元素放入队列会调用notEmpty.signal()进行唤醒),那为什么需要使用while呢?因为insert后lock.unlock,未必notEmpty.await()立即被喚醒,可能之前插入一個執行緒運行remove方法
notEmpty.signal()
lock.unlock
“notEmpty.await()方法既然甦醒返回了 ,那麼此線程肯定拿到了 lock” 這句話是正確的。
假設你寫的程式碼是:
可以明確的一點就是我們需要保證在
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》第二版第 69 條(244 頁)。所以在你這段程式碼裡目前隊列為空時(count==0),呼叫了
notEmpty.await()
,这段代码对锁是有影响的,实际上底层上已经释放了锁,只是这个方法保证了被唤醒时一定又能够拿回锁(当有元素放入队列会调用notEmpty.signal()
进行唤醒),那为什么需要使用while呢?因为insert后lock.unlock
,未必notEmpty.await()
立即被喚醒,可能之前插入一個執行緒運行remove方法