10

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.

Sergey Kalinichenko
  • 714,442
  • 84
  • 1,110
  • 1,523
sdindiver
  • 491
  • 1
  • 5
  • 19

1 Answers1

6

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).

Sergey Kalinichenko
  • 714,442
  • 84
  • 1,110
  • 1,523
  • Could you please elaborate a little bit by "if you are not careful with multiple instances of such blocking queue, your system may end up deadlocking" – sdindiver Apr 16 '18 at 06:57
  • @sdindiver I was unable to come up with an example of deadlocking, so I replaced the text with a demo showing some timing differences between locking vs. lock-free queues. – Sergey Kalinichenko Apr 16 '18 at 13:33
  • interesting, so you are saying the extra locking overhead is slower and thur has more "failed" polls, and that costs the extra run time? – gdlamp Jun 20 '20 at 14:12
  • @gdlamp Yes, that's essentially what I think is going on. Locking increases the run time, and the fraction of "failed" polls goes up with it. – Sergey Kalinichenko Jun 20 '20 at 19:46