Admiring and Understanding LinkedBlockingQueue take Method

Admiring and Understanding LinkedBlockingQueue take Method

In order to admire the code of the implementation of the BlockingQueue, lets have a look at the LinkedBlockingQueue take method.

Lets go through the code line by line, understanding the role of each line of code.

Line 4:
final AtomicInteger count = this. count;
In case you already know, AtomicInteger is used for atomic modifications to integers. It offers operations like increment and decrement in a thread safe way.
Line 5:

final ReentrantLock takeLock = this. takeLock;
This lock is used as a monitor for synchronizing the take or pop, basically for synchronizing the read operation on the queue.
Line 6:

Here the read operations are locked, unless the read operation is performed successfully.
Line 7:
This particular try is not basically used as an exception handler, but is used with finally block to release/reset all the resources. As you can see, in the corresponding finally block, the takeLock lock is unlocked.
Line 9 and 10:
while (count.get() == 0)
notEmpty is a condition of the lock takeLock, which receives a signal from write operation methods say put and offer. Here the thread is suspended unless the queue is not empty. Even on receiving a signal that the queue is not empty, we check that the count is not zero. This is important in a threaded environment.
Line 11:

catch (InterruptedException ie) {
     notEmpty.signal(); // propagate to a non-interrupted thread
     throw ie;
In case of an interruption, the other threads are signaled to proceed. And an exception is throw in this thread.
Line 16:

x = extract();
This is the part where the magic happens. You must be familiar with a linked list, here the first item of the linked list is extracted and the head of the linked list is updated.

     * Removes a node from head of queue,
     * @return the node
    private E extract () {
        Node<E> first = head. next;
        head = first;
        E x = first. item;
        first. item = null;
        return x;
Line 17:

c = count .getAndDecrement();

Here the actual count is updated, it is decremented preserving the count before extraction.Line 18:
if (c > 1)

In case the size of the queue was more than 1 before extraction, then other threads are signaled that the queue still has elements which are waiting to be extracted.Line 23:
if (c == capacity )
In case, the queue was full before extraction, we signal the threads waiting to write to the queue to go ahead, as the extraction has made way for another element.Line 25:

return x;

In order to make sure that there is only a single exit point of a method which returns something, we usually create an object which acts as the object that is to be returned. Similarly in line 2, we declare x with the same data type which was to be returned.Thanks for reading. I know you can’t hold back to read the source code of the LinkedBlockingQueue. Please go ahead and read the source code, try out some samples.