Como faço para usar um ConcurrentLinkedQueue
em Java?
Usando isso LinkedQueue
, preciso me preocupar com a simultaneidade na fila? Ou eu apenas tenho que definir dois métodos (um para recuperar elementos da lista e outro para adicionar elementos à lista)?
Nota: obviamente, esses dois métodos devem ser sincronizados. Certo?
EDIT: O que estou tentando fazer é o seguinte: Eu tenho uma classe (em Java) com um método para recuperar itens da fila e outra classe com um método para adicionar itens à fila. Os itens adicionados e recuperados da lista são objetos de minha própria classe.
Mais uma pergunta: preciso fazer isso no método de remoção:
while (queue.size() == 0){
wait();
queue.poll();
}
Tenho apenas um consumidor e um produtor.
java
concurrency
Ricardo Felgueiras
fonte
fonte
Respostas:
Não, os métodos não precisam ser sincronizados e você não precisa definir nenhum método; eles já estão em ConcurrentLinkedQueue, basta usá-los. ConcurrentLinkedQueue faz todo o bloqueio e outras operações de que você precisa internamente; o (s) seu (s) produtor (es) adiciona (m) dados à fila e seus consumidores fazem pesquisas para isso.
Primeiro, crie sua fila:
Agora, onde quer que você esteja criando seus objetos produtor / consumidor, passe na fila para que eles tenham um lugar para colocar seus objetos (você poderia usar um setter para isso, mas eu prefiro fazer esse tipo de coisa em um construtor):
e:
e adicione coisas a ele em seu produtor:
e retire as coisas em seu consumidor (se a fila estiver vazia, poll () retornará nulo, então verifique):
Para mais informações veja o Javadoc
EDITAR:
Se você precisa bloquear a espera para que a fila não fique vazia, você provavelmente deseja usar um LinkedBlockingQueue e usar o método take (). No entanto, LinkedBlockingQueue tem uma capacidade máxima (o padrão é Integer.MAX_VALUE, que é mais de dois bilhões) e, portanto, pode ou não ser apropriado dependendo das circunstâncias.
Se você tiver apenas um thread colocando coisas na fila e outro thread retirando coisas da fila, ConcurrentLinkedQueue provavelmente é um exagero. É mais para quando você pode ter centenas ou mesmo milhares de threads acessando a fila ao mesmo tempo. Provavelmente, suas necessidades serão atendidas usando:
Uma vantagem disso é que ele bloqueia na instância (fila), para que você possa sincronizar na fila para garantir a atomicidade das operações compostas (conforme explicado por Jared). Você NÃO PODE fazer isso com um ConcurrentLinkedQueue, pois todas as operações são feitas SEM bloqueio na instância (usando variáveis java.util.concurrent.atomic). Você NÃO precisará fazer isso se quiser bloquear enquanto a fila estiver vazia, porque poll () simplesmente retornará nulo enquanto a fila estiver vazia, e poll () é atômico. Verifique se poll () retorna nulo. Se isso acontecer, espere () e tente novamente. Não há necessidade de bloquear.
Finalmente:
Honestamente, eu apenas usaria um LinkedBlockingQueue. Ainda é um exagero para o seu aplicativo, mas provavelmente funcionará bem. Se não tiver desempenho suficiente (PERFIL!), Você sempre pode tentar outra coisa, e isso significa que você não precisa lidar com NENHUM material sincronizado:
Tudo o resto é o mesmo. Put provavelmente não bloqueará, porque você provavelmente não colocará dois bilhões de objetos na fila.
fonte
Collection.synchronizedList
retorna umList
que não implementaQueue
.ConcurrentLinkedQueue
para Produtor Consumidor uma boa ideia, estou me referindo a esta postagem stackoverflow.com/questions/1426754/…Esta é em grande parte uma duplicata de outra pergunta .
Esta é a seção da resposta que é relevante para esta pergunta:
Preciso fazer minha própria sincronização se usar java.util.ConcurrentLinkedQueue?
As operações atômicas nas coleções simultâneas são sincronizadas para você. Em outras palavras, cada chamada individual para a fila é garantida com thread-safe, sem qualquer ação de sua parte. O que não é garantido como thread-safe são quaisquer operações que você executa na coleção que não são atômicas.
Por exemplo, isso é threadsafe sem qualquer ação de sua parte:
ou
Contudo; chamadas não atômicas para a fila não são automaticamente thread-safe. Por exemplo, as seguintes operações não são automaticamente threadsafe:
Este último não é thread-safe, pois é muito possível que entre o momento em que isEmpty é chamado e o momento em que a enquete é chamada, outros threads tenham adicionado ou removido itens da fila. A maneira threadsafe de fazer isso é assim:
Novamente ... chamadas atômicas para a fila são automaticamente thread-safe. Chamadas não atômicas não são.
fonte
Use poll para obter o primeiro elemento e add para adicionar um novo último elemento. É isso, sem sincronização ou qualquer outra coisa.
fonte
Isso é provavelmente o que você está procurando em termos de segurança de thread e "beleza" ao tentar consumir tudo na fila:
Isso garantirá que você feche quando a fila estiver vazia e que continue a retirar objetos dela, desde que não esteja vazia.
fonte
O ConcurentLinkedQueue é uma implementação livre de espera / bloqueio muito eficiente (consulte o javadoc para referência), então não só você não precisa sincronizar, mas a fila não bloqueará nada, sendo virtualmente tão rápida quanto uma não sincronizada (não thread seguro) um.
fonte
Basta usá-lo como faria com uma coleção não simultânea. As classes Concurrent [Collection] envolvem as coleções regulares para que você não precise se preocupar em sincronizar o acesso.
Edit: ConcurrentLinkedList não é apenas um invólucro, mas uma implementação simultânea melhor. De qualquer forma, você não precisa se preocupar com a sincronização.
fonte