Middle
Como organizar a troca de dados entre dois threads em Java?
sobes.tech IA
Resposta da IA
A troca de dados entre threads em Java pode ser organizada das seguintes formas:
- Variáveis partilhadas com sincronização: Os threads usam variáveis partilhadas, cujo acesso é sincronizado usando a palavra-chave
synchronized, bloqueios (Lockdejava.util.concurrent.locks) ou variáveis atómicas (Atomicdejava.util.concurrent.atomic). - Túneis de dados (Streams ligados): Os fluxos de entrada/saída ligados (
PipedInputStreamePipedOutputStream) permitem que um thread escreva dados e outro os leia.// Uso de Streams ligados try { PipedOutputStream pout = new PipedOutputStream(); PipedInputStream pin = new PipedInputStream(pout); // Thread 1: escrita new Thread(() -> { try { pout.write("Olá do thread 1".getBytes()); pout.close(); } catch (Exception e) { e.printStackTrace(); } }).start(); // Thread 2: leitura new Thread(() -> { try { int data; while ((data = pin.read()) != -1) { System.out.print((char) data); } pin.close(); } catch (Exception e) { e.printStackTrace(); } }).start(); } catch (Exception e) { e.printStackTrace(); } - Filas (Queues): O uso de coleções seguras para threads, como
BlockingQueue(por exemplo,ArrayBlockingQueue,LinkedBlockingQueue), permite que um thread coloque elementos na fila e outro os retire.import java.util.concurrent.BlockingQueue; import java.util.concurrent.LinkedBlockingQueue; // Uso de BlockingQueue BlockingQueue<String> queue = new LinkedBlockingQueue<>(); // Produtor new Thread(() -> { try { queue.put("Mensagem 1"); queue.put("Mensagem 2"); } catch (InterruptedException e) { Thread.currentThread().interrupt(); } }).start(); // Consumidor new Thread(() -> { try { System.out.println(queue.take()); System.out.println(queue.take()); } catch (InterruptedException e) { Thread.currentThread().interrupt(); } }).start(); - Mecanismos
wait(),notify(),notifyAll(): São usados para sincronizar threads com base em monitores de objetos. Uma thread chamawait()para esperar por uma condição, outra chamanotify()ounotifyAll()para notificar threads em espera sobre uma mudança de condição.// Uso de wait/notify class Data { private String message; private boolean empty = true; public synchronized String read() { while (empty) { try { wait(); // Espera por dados } catch (InterruptedException e) { Thread.currentThread().interrupt(); } } empty = true; notifyAll(); // Notifica que pode escrever return message; } public synchronized void write(String message) { while (!empty) { try { wait(); // Espera que os dados anteriores sejam lidos } catch (InterruptedException e) { Thread.currentThread().interrupt(); } } empty = false; this.message = message; notifyAll(); // Notifica novos dados } } CompletableFuture: Permite criar cálculos assíncronos e combiná-los, facilitando a troca de dados através de valores de retorno e manipuladores de finalização.Exchanger: Permite que dois threads troquem objetos num ponto de sincronização.
A escolha de um método específico depende da natureza da tarefa, do nível de sincronização necessário, do desempenho e da complexidade de implementação.