LinkedBlockingQueue vs ConcurrentLinkedQueue
-
07-07-2019 - |
Pergunta
A minha pergunta relaciona-se com esta pergunta ??a > pediu mais cedo. Em situações onde eu estou usando uma fila para a comunicação entre produtores e consumidores tópicos que as pessoas geralmente recomendo usar LinkedBlockingQueue
ou ConcurrentLinkedQueue
?
Quais são as vantagens / desvantagens de usar um sobre o outro?
A principal diferença que eu posso ver de uma perspectiva API é que uma LinkedBlockingQueue
pode ser opcionalmente limitado.
Solução
Para um thread de produtor / consumidor, não estou certo de que ConcurrentLinkedQueue
é ainda uma opção razoável - não implementar BlockingQueue
, que é a interface fundamental para filas de produtor / consumidor IMO. Você teria que chamar poll()
, espere um pouco, se você não tinha encontrado nada, e depois consultar novamente etc ... levando a atrasos quando um novo item chega, e ineficiências quando ele está vazio (devido a acordar desnecessariamente de sonos ).
De docs para BlockingQueue:
implementações
BlockingQueue
são projetados para ser usado principalmente para filas produtor-consumidor
Eu sei que não faz estritamente dizer que as filas única bloqueio deve ser usado para filas produtor-consumidor, mas mesmo assim ...
Outras dicas
Esta questão merece uma resposta melhor.
ConcurrentLinkedQueue
de Java é baseado no famoso algoritmo por Maged M. Michael e Michael L. Scott para sem bloqueio sem bloqueio filas .
"sem bloqueio" como um termo aqui para um recurso sustentou (nossa fila) significa que, independentemente do que programador da plataforma faz, como interromper um fio, ou se o fio em questão é simplesmente muito lento, outros segmentos disputando o mesmo recurso ainda será capaz de progredir. Se um bloqueio está envolvido, por exemplo, o thread que bloqueou poderia ser interrompido e todos os segmentos de espera para que o bloqueio seria bloqueado. fechaduras intrínsecas (a palavra-chave synchronized
) em Java também pode vir com uma pena severa para o desempenho - como quando tendenciosa bloqueio está envolvido e você tem contenda, ou depois da VM decide 'inflar' o bloqueio após um período de rotação graça e bloco alegando tópicos ... é por isso que em muitos contextos (cenários de baixa / médio de contenção), fazendo comparar-e-conjuntos em referências atômicas pode ser muito mais eficiente e isso é exatamente o que muitos não-bloqueando dados-estruturas estão a fazer.
ConcurrentLinkedQueue
de Java não é apenas para não-bloqueio, mas tem a propriedade impressionante que o produtor não lidar com o consumidor. Em um cenário único produtor / único consumidor (SPSC), isso realmente significa que não haverá disputa para falar. Em um cenário de consumo produtor / única múltipla, o consumidor não vai competir com os produtores. Essa fila tem disputa quando vários produtores tentam offer()
, mas isso é a concorrência por definição. É basicamente um propósito geral e eficiente fila non-blocking.
Como para não ser um BlockingQueue
, bem, bloqueando um fio que esperar em uma fila é uma maneira assustadoramente terrível de projetar sistemas concorrentes. não. Se você não consegue descobrir como usar um ConcurrentLinkedQueue
em um cenário consumidor / produtor, em seguida, basta mudar para abstrações de nível superior, como um bom quadro ator.
blocos LinkedBlockingQueue
o consumidor ou o produtor quando a fila está vazio ou cheio eo respectivo segmento consumidor / produtor é posto para dormir. Mas este recurso de bloqueio vem com um custo:. Cada venda ou levá operação é bloqueio sustentou entre os produtores ou consumidores (se muitos), portanto, em cenários com muitos produtores / consumidores a operação pode ser mais lenta ??p>
ConcurrentLinkedQueue
não está usando bloqueios, mas CAS , por sua put / take operações potencialmente reduzindo a contenção com muitos segmentos produtores e consumidores. Mas sendo um "esperar free" estrutura de dados, ConcurrentLinkedQueue
não vai bloquear quando vazio, o que significa que o consumidor terá de lidar com a take()
retornando valores null
por "espera ocupada", por exemplo, com o segmento do consumidor comendo CPU.
Então, qual é o "melhor" depende do número de segmentos de consumo, sobre a taxa que consomem / produção, etc. A referência é necessário para cada cenário.
Um caso de uso particular quando o ConcurrentLinkedQueue
é claramente melhor é quando os produtores primeiro produzir algo e terminar seu trabalho, colocando o trabalho na fila de e só depois os consumidores começa a consumir, sabendo que eles vão ser feito quando fila está vazia. (Aqui há concorrência entre produtores e consumidores, mas apenas entre o produtor-produtor e consumidor-consumidor)
Outra solução (que não escala bem) é canais ENCONTRO: java.util.concurrent SynchronousQueue
Se a sua fila não é expansível e contém apenas um produtor / thread consumidor. Você pode usar lockless fila (Você não precisa para bloquear o acesso aos dados).