In this section from java.util.concurrent.LinkedBlockingQueue.put() method, I think there is no need of AtomicInteger. Considering there is only one thread inside lock(). Am I correct?
putLock.lockInterruptibly();
try {
while (count.get() == capacity) {
notFull.await();
}
enqueue(node);
c = count.getAndIncrement();
if (c + 1 < capacity)
notFull.signal();
} finally {
putLock.unlock();
}
I checked many questions, but can not find answer. My question: there is only one thread inside lock, so why to use AtomicInteger here
The LinkedBlockingQueue
uses two different locks, putLock
and takeLock
to allow concurrent put
and take
operation to proceed without blocking each other, assuming that there are already nodes in the queue but the capacity has not exhausted (or not limited at all).
So it this case, count
may be accessed by two threads concurrently. Since the consumer and producer threads use different locks, the locks themselves do not establish the necessary memory visibility guarantees between the producer and consumer, it is in fact the atomic update of the count
which does.
Besides that, there are also non-blocking operations, like size()
or remainingCapacity()
which access count
without holding a lock. Also, some operations, like peek()
and poll()
(without timeout) have a short-cut, testing count
for zero before acquiring the lock, to return null
immediately without locking when the count is zero.
There are two locks there:
private final ReentrantLock putLock = new ReentrantLock();
private final ReentrantLock takeLock = new ReentrantLock();
The put
method is indeed protected by the putLock
, but any other thread accessing count
can still update it (unless it's another put
). To make sure it is correctly updated it has to be Atomic
.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With