LinkedBlockingQueue
bloqueia o consumidor ou o produtor quando a fila está vazia ou cheia e o respectivo segmento de consumidor / produtor é colocado em hibernação. Mas esse recurso de bloqueio tem um custo: cada operação de colocação ou retirada é disputada por bloqueio entre os produtores ou consumidores (se houver), portanto, em cenários com muitos produtores / consumidores, a operação pode ser mais lenta.
ConcurrentLinkedQueue
não está usando bloqueios, mas CAS , em suas operações put / take potencialmente reduzindo a contenção com muitos encadeamentos de produtor e consumidor. Porém, sendo uma estrutura de dados "livre de espera", ConcurrentLinkedQueue
não será bloqueada quando vazia, o que significa que o consumidor precisará lidar com os valores take()
retornados null
por "espera ocupada", por exemplo, com a thread do consumidor consumindo CPU.
Então, qual é "melhor" depende do número de threads de consumo, da taxa que eles consomem / produzem, etc. Um benchmark é necessário para cada cenário.
Um caso de uso específico em que o ConcurrentLinkedQueue
é claramente melhor é quando os produtores primeiro produzem algo e terminam seu trabalho, colocando o trabalho na fila, e somente depois que os consumidores começam a consumir, sabendo que o farão quando a fila estiver vazia. (aqui não há concorrência entre produtor-consumidor, mas apenas entre produtor-produtor e consumidor-consumidor)