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