Middle
Jak lze zorganizovat výměnu dat mezi dvěma vlákny v Java?
sobes.tech AI
Odpověď od AI
Způsoby výměny dat mezi vlákny v Javě lze organizovat následujícími způsoby:
- Sdílené proměnné se synchronizací: Vlákna používají sdílené proměnné, ke kterým přistupují synchronizovaně pomocí klíčového slova
synchronized, zámků (Lockzjava.util.concurrent.locks) nebo atomických proměnných (Atomiczjava.util.concurrent.atomic). - Datové pipy (Piped Streams): Propojené vstupní/výstupní proudy (
PipedInputStreamaPipedOutputStream) umožňují jednomu vláknu zapisovat data, zatímco jiné je čte.// Použití Piped Streams try { PipedOutputStream pout = new PipedOutputStream(); PipedInputStream pin = new PipedInputStream(pout); // Vlákno 1: zápis new Thread(() -> { try { pout.write("Ahoj z vlákna 1".getBytes()); pout.close(); } catch (Exception e) { e.printStackTrace(); } }).start(); // Vlákno 2: čtení 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(); } - Fronty (Queues): Použití bezpečných kolekcí pro vlákna, jako je
BlockingQueue(napříkladArrayBlockingQueue,LinkedBlockingQueue), umožňuje jednomu vláknu vkládat prvky do fronty a jinému je odebírat.import java.util.concurrent.BlockingQueue; import java.util.concurrent.LinkedBlockingQueue; // Použití BlockingQueue BlockingQueue<String> queue = new LinkedBlockingQueue<>(); // Výrobce new Thread(() -> { try { queue.put("Zpráva 1"); queue.put("Zpráva 2"); } catch (InterruptedException e) { Thread.currentThread().interrupt(); } }).start(); // Spotřebitel new Thread(() -> { try { System.out.println(queue.take()); System.out.println(queue.take()); } catch (InterruptedException e) { Thread.currentThread().interrupt(); } }).start(); - Mechanismy
wait(),notify(),notifyAll(): Používají se pro synchronizaci vláken na základě monitorů objektů. Jedno vlákno voláwait()pro čekání na podmínku, jiné volánotify()nebonotifyAll()pro oznámení čekajícím vláknům o změně podmínky.// Použití wait/notify class Data { private String message; private boolean empty = true; public synchronized String read() { while (empty) { try { wait(); // Čekání na data } catch (InterruptedException e) { Thread.currentThread().interrupt(); } } empty = true; notifyAll(); // Oznámení o možnosti zápisu return message; } public synchronized void write(String message) { while (!empty) { try { wait(); // Čekání, dokud se nepřečtou předchozí data } catch (InterruptedException e) { Thread.currentThread().interrupt(); } } empty = false; this.message = message; notifyAll(); // Oznámení o nových datech } } CompletableFuture: Umožňuje vytvářet asynchronní výpočty a spojovat jejich výsledky, zajišťující výměnu dat prostřednictvím vrácených hodnot a handlerů dokončení.Exchanger: Umožňuje dvěma vláknům vyměnit objekty v bodě synchronizace.
Výběr konkrétní metody závisí na specifikách úkolu, požadované úrovni synchronizace, výkonu a složitosti implementace.