The source code of put
method of LinkedBlockingQueue
in JDK 1.8:
public void put(E e) throws InterruptedException {
if (e == null) throw new NullPointerException();
// Note: convention in all put/take/etc is to preset local var
// holding count negative to indicate failure unless set.
int c = -1;
Node<E> node = new Node<E>(e);
final ReentrantLock putLock = this.putLock;
final AtomicInteger count = this.count;
putLock.lockInterruptibly();
try {
/*
* Note that count is used in wait guard even though it is
* not protected by lock. This works because count can
* only decrease at this point (all other puts are shut
* out by lock), and we (or some other waiting put) are
* signalled if it ever changes from capacity. Similarly
* for all other uses of count in other wait guards.
*/
while (count.get() == capacity) {
notFull.await();
}
enqueue(node);
c = count.getAndIncrement();
if (c + 1 < capacity)
notFull.signal(); // Is this necessary?
} finally {
putLock.unlock();
}
if (c == 0)
signalNotEmpty();
}
Why does the current producer need wake up other producers by notFull.signal()
when the consumers would do that after they taking elements from the queue? Is there any example can explain this is necessary?
I'm not sure whether this is possible.
Producer P1, P2(timed) and P3 are blocking at notFull.await();
.
Consumer C1 consumers one element and wakes up P1.
P1 is going to put elements in the queue. Meanwhile C2 consumers another element and wakes up P2. Since P1 is holding the putLock
, P2 has to wait. Unfortunately, P2 times out while waiting.
P1 needs to wake up P3, otherwise P3 would wait unnecessarily.