Skip to content

What does “Aren’t allocating the things put into queues” mean?

I’m reading this:

https://concurrency.markmail.org/search/?q=ArrayBlockingQueue+LinkedBlockingQueue#query:ArrayBlockingQueue%20LinkedBlockingQueue%20from%3A%22Doug%20Lea%22+page:1+mid:sgx3amdfga7esqul+state:results

In which Doug Lea says:

Usually, when you are putting something into a queue, you will have just allocated that new something. And similarly, when you take something out you usually use it and then let it become garbage. In which case the extra allocation for a queue node is not going to make much difference in overall GC, so you might as well go for the better scalability of LinkedBlockingQueue. I think this is the most common use case.

But, if you aren’t allocating the things put into queues, and don’t expect lots of threads to be contending when the queue is neither empty nor full, then ArrayBlockingQueue is likely to work better.

I want to know what does Aren't allocating the things put into queues mean?

Also, this sentence: don't expect lots of threads to be contending when the queue is neither empty nor full, then ArrayBlockingQueue is likely to work better, can someone explain that a little bit more specifically?

Answer

To me that seems to mean following:

  1. I want to know what does Aren't allocating the things put into queues mean?

    This is about the GC overhead which they discus.

    LinkedBlockingQueue creates new internal Node object for every added item, which means it generates garbage and, as a result, causes garbage collection (GC).
    Doug says that often the items we store in a queue are objects which:

    • are created right before they are added to the queue
    • become unused (and eligible for GC) shortly after they are removed from the queue

    In these cases the items themselves cause GC anyway, therefore it’s not a problem that Node objects require GC as well.

    But if you only store long-lived objects in a queue, then LinkedBlockingQueue might become the only thing that causes GC.
    Then you might want to use ArrayBlockingQueue instead to avoid GC.
    (ArrayBlockingQueue doesn’t create any objects when items added/removed)

  2. Also, this sentence: don't expect lots of threads to be contending when the queue is neither empty nor full, then ArrayBlockingQueue is likely to work better, can someone explain that a little bit more specifically?

    LinkedBlockingQueue uses two locks: one for put() and one for take().
    ArrayBlockingQueue uses one lock for both put() and take().
    As a result when “the queue is neither empty nor full” (i.e. when neither put() nor take() have to wait) and there are two threads: one executes put(), another one executes take()

    • if the queue is LinkedBlockingQueue, then the threads don’t block each other
    • if the queue is ArrayBlockingQueue, then one thread will have to wait until the other one is done