JavaRush /Blogue Java /Random-PT /Exemplo de SynchronousQueue em Java - resolvendo o proble...
profeg
Nível 18

Exemplo de SynchronousQueue em Java - resolvendo o problema Produtor Consumidor

Publicado no grupo Random-PT
Exemplo de SynchronousQueue em Java - resolvendo o problema Produtor Consumidor
SynchronousQueue é um tipo especial de BlockingQueue em que cada operação de inserção deve aguardar um comando de remoção correspondente em outro thread e vice-versa. Quando você chama o método put() em um SynchronousQueue, ele é bloqueado até que outro thread retire esse elemento dele. Da mesma forma, se outro thread tentar remover um elemento dele e o elemento não estiver lá, esse thread será bloqueado até que o outro thread coloque o elemento na fila. Você pode pensar em SynchronousQueue como um atleta ( thread ) correndo com a tocha olímpica, ele corre com a tocha (o objeto que está sendo passado) e passa para outro atleta que está esperando do outro lado. Se você prestar atenção ao nome, entenderá que SynchronousQueue tem esse nome por um motivo: ele transfere dados de forma síncrona para outro thread ; espera que alguém colete os dados em vez de apenas colocá-los e sair (uma operação assíncrona). Se você conhece CSP e Ada, sabe que as filas sincronizadas são semelhantes ao encontro de threads. Eles são adequados para construções de transferência de controle nas quais um objeto em execução em um thread deve sincronizar com um objeto em outro thread para passar alguma informação, evento ou tarefa para ele. Nos tutoriais anteriores de programação multithread, aprendemos como resolver o problema produtor-consumidor usando os métodos wait and notify e BlockingQueue . Agora aprenderemos como aplicar o padrão produtor-consumidor usando SynchronousQueue. Esta classe também oferece suporte a um comportamento justo para ordenar as esperas dos threads produtores e consumidores. Por padrão, esta ordem não é garantida. Entretanto, filas criadas com propriedades justas garantem acesso para threads em uma fila FIFO (Firs In First Out).
Produtor/Consumidor usando SynchronousQueue em Java.
Exemplo de SynchronousQueue em Java - resolvendo o problema Produtor Consumidor - 1 Como eu disse acima, não há nada melhor do que o problema produtor-consumidor para entender a comunicação entre threads em qualquer linguagem de programação. Neste problema, um thread atua como produtor que produz eventos e tarefas, e o outro thread atua como consumidor deles. Um buffer compartilhado é usado para transferir dados do produtor para o consumidor. A dificuldade de resolver este problema surge em casos extremos, por exemplo, quando o fabricante é obrigado a esperar porque... o buffer está cheio ou o consumidor é forçado a esperar porque o buffer está vazio. Isso foi facilmente resolvido, porque... A fila de bloqueio forneceu não apenas um buffer para armazenar dados, mas também controle de fluxo, bloqueando o thread que chama o método put() (Produtor) se o buffer estiver cheio, e bloqueando o thread que chama o método take() (Consumidor) se o buffer estava vazio. Agora resolveremos esse mesmo problema usando SynchronousQueue, um tipo especial de coleção paralela com capacidade zero. No exemplo a seguir, temos dois threads chamados PRODUCER e CONSUMER (sempre dê nomes aos threads, esse é um estilo muito bom de programação multithread) O primeiro thread posta a pontuação do jogo e o segundo thread a consome. A pontuação do jogo nada mais é do que um objeto do tipo String. Mas se você executar o programa com um tipo diferente, não notará nenhuma diferença. Para entender como SynchronousQueue funciona e como resolver o problema produtor-consumidor, você precisa: executar o programa para depuração (depuração) no ambiente Eclipse ou simplesmente iniciar o thread do produtor comentando consumer.start(); se o encadeamento consumidor não estiver em execução, o encadeamento produtor será bloqueado em queue.put(event); se estiver em execução, você não poderá ver o produtor [PRODUCER] publicando o evento :FOUR. Isso acontece porque comportamento específico de SynchronousQueue, que garante que os dados de postagem do thread serão bloqueados até que outro thread receba os dados e vice-versa. Você pode testar o restante do código comentando Producer.start(); e iniciando apenas o thread do consumidor. Se você estudar cuidadosamente o que o programa produz, notará que a ordem da saída é invertida. Parece que o thread [CONSUMER] obteve os dados antes que o thread [PRODUCER] os produzisse. Isso ocorre porque SynchronousQueue não garante o enfileiramento por padrão. Mas possui regras de justiça que definem o acesso aos threads na ordem FIFO. Você pode ativar essas regras passando true para o construtor SynchronousQueue sobrecarregado assim: import java.util.concurrent.SynchronousQueue; /** * Java Program to solve Producer Consumer problem using SynchronousQueue. A * call to put() will block until there is a corresponding thread to take() that * element. * * @author Javin Paul */ public class SynchronousQueueDemo{ public static void main(String args[]) { final SynchronousQueue queue = new SynchronousQueue (); Thread producer = new Thread("PRODUCER") { public void run() { String event = "FOUR"; try { queue.put(event); // thread will block here System.out.printf("[%s] published event : %s %n", Thread .currentThread() .getName(), event); } catch (InterruptedException e) { e.printStackTrace(); } } }; producer.start(); // starting publisher thread Thread consumer = new Thread("CONSUMER") { public void run() { try { String event = queue.take(); // thread will block here System.out.printf("[%s] consumed event : %s %n", Thread .currentThread() .getName(), event); } catch (InterruptedException e) { e.printStackTrace(); } } }; consumer.start(); // starting consumer thread } } Output: [CONSUMER] consumed event : FOUR [PRODUCER] published event : FOUR new SynchronousQueue(boolean fair).
O que você precisa lembrar sobre SynchronousQueue em Java.

Aqui estão algumas propriedades importantes desse tipo especial de fila de bloqueio em Java. É muito útil passar dados de um thread para outro de maneira sincronizada. Esta fila não tem capacidade e fica bloqueada até que outro thread a libere.

  1. SynchronousQueue bloqueia e até que um thread esteja pronto para receber dados, outro tentará colocar dados.
  2. SynchronousQueue não tem volume. Ou seja, não contém dados.
  3. SynchronousQueue é usado para implementar uma estratégia de enfileiramento direto, onde um thread passa o controle para um thread em espera ou cria um novo, se permitido, caso contrário, o controle não é transferido.
  4. Esta fila não permite dados nulos. Uma tentativa de adicionar um elemento nulo gerará um NullPointerException .
  5. Se você usar outros métodos de Collection (como contains), SynchronousQueue se comportará como uma coleção vazia.
  6. Você não pode usar o método peek de SynchronousQueue porque o elemento só existe quando você tenta removê-lo; Além disso, você não poderá inserir elementos (usando qualquer método) até que outro thread tente removê-lo.
  7. Você não poderá usar o iterador para SynchronousQueue porque... não tem elementos.
  8. SynchronousQueue pode ser criado com regras justas onde o acesso aos threads é garantido na ordem FIFO.
Talvez tudo isso seja sobre SynchronousQueue em Java. Vimos alguns dos recursos especiais dessa coleção multithread e aprendemos como resolver o clássico problema produtor-consumidor usando SynchronousQueue em Java. A propósito, chamá-lo de Fila não é totalmente correto, porque... não contém elementos. A chamada para put() não será concluída até que outro thread chame take(). É mais correto pensar nele como um ponto de encontro de threads, onde eles compartilham um objeto. Em outras palavras, é um utilitário para passagem sincronizada de objetos em Java, talvez uma alternativa mais segura ao método wait and notify .
Comentários
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION