Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why use ConcurrentLinkedQueue when we have LinkedBlockingQueue?

Why would I use ConcurrentLinkedQueue when I have LinkedBlockingQueue? I know ConcurrentLinkedQueue is non blocking but LinkedBlockingQueue can be worked as ConcurrentLinkedQueue. I would use put()/offer() method for insertion and poll() method for removal. poll() method does not wait if queue is empty. LinkedBlockingQueue is unbounded as well. So I can use this.

The difference I found so far is ConcurrentLinkedQueue is using hardware level synchronization mechanism with compare and swap while LinkedBlockingQueue is using ReentrantLock.

like image 371
sdindiver Avatar asked Apr 15 '18 14:04

sdindiver


People also ask

What is LinkedBlockingQueue used for?

LinkedBlockingQueue blocks the consumer or the producer when the queue is empty or full and the respective consumer/producer thread is put to sleep.

What is ConcurrentLinkedQueue?

ConcurrentLinkedQueue is an unbounded thread-safe queue which arranges the element in FIFO. New elements are added at the tail of this queue and the elements are added from the head of this queue. ConcurrentLinkedQueue class and its iterator implements all the optional methods of the Queue and Iterator interfaces.

Why do we need BlockingQueue?

Here we have a blockingQueue that has a capacity equal to 10. It means that when a producer tries to add an element to an already full queue, depending on a method that was used to add it (offer(), add() or put()), it will block until space for inserting object becomes available. Otherwise, the operations will fail.


1 Answers

The main difference is that ConcurrentLinkedQueue is wait-free, not merely lock-free (what's the difference?) while LinkedBlockingQueue must remain locking by its very nature.

You can model ConcurrentLinkedQueue with LinkedBlockingQueue and poll, but the implementation would remain locking, reducing the concurrency that you could get out of your system.

Here is an admittedly imprecise microbenchmark that checks the speed of passing 10,000 objects through each of the two concurrent queues without blocking, and counting the total number of calls to poll() in a loop:

AtomicInteger total = new AtomicInteger();
ConcurrentLinkedQueue<Integer> q = new ConcurrentLinkedQueue<>();
Thread thread = new Thread(() -> {
    int remaining = 10000;
    while (remaining != 0) {
        total.incrementAndGet();
        if (q.poll() != null) {
            remaining--;
        }
    }
});
Integer[] first100 = new Integer[100];
for (int i = 0 ; i != 100 ; i++) {
    first100[i] = i;
}
long start = System.nanoTime();
thread.start();
for (int i = 0 ; i != 10000 ; i++) {
    q.add(first100[i%100]);
}
thread.join();
long runtime = System.nanoTime() - start;

The idea is to measure queue's "throughput" in the absence of other processing. This task completes in 11.23 ms with 60K iterations in the reading thread (demo 1) with ConcurrentLinkedQueue, and 23,46 ms / 100K iterations with LinkedBlockingQueue (demo 2).

like image 120
Sergey Kalinichenko Avatar answered Sep 18 '22 01:09

Sergey Kalinichenko