Sobes.tech
Middle

Как да организираме обмена на данни между два потока в Java?

sobes.tech AI

Отговор от AI

Начините за обмен на данни между нишки в Java могат да бъдат организирани по следния начин:

  • Общи променливи с синхронизация: Нишките използват общи променливи, към които се достъпва синхронизирано с ключовата дума synchronized, блокове (Lock от java.util.concurrent.locks) или атомарни променливи (Atomic от java.util.concurrent.atomic).
  • Данни конвейери (Piped Streams): Свързани входно/изходни потоци (PipedInputStream и PipedOutputStream) позволяват на един поток да записва данни, а на друг да ги чете.
    // Използване на Piped Streams
    try {
        PipedOutputStream pout = new PipedOutputStream();
        PipedInputStream pin = new PipedInputStream(pout);
    
        // Поток 1: запис
        new Thread(() -> {
            try {
                pout.write("Здравей от поток 1".getBytes());
                pout.close();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }).start();
    
        // Поток 2: четене
        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();
    }
    
  • Опашки (Queues): Използването на безопасни за нишки колекции като BlockingQueue (например, ArrayBlockingQueue, LinkedBlockingQueue) позволява на един поток да поставя елементи в опашката, а друг да ги извлича.
    import java.util.concurrent.BlockingQueue;
    import java.util.concurrent.LinkedBlockingQueue;
    
    // Използване на BlockingQueue
    BlockingQueue<String> queue = new LinkedBlockingQueue<>();
    
    // Производител
    new Thread(() -> {
        try {
            queue.put("Съобщение 1");
            queue.put("Съобщение 2");
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
        }
    }).start();
    
    // Потребител
    new Thread(() -> {
        try {
            System.out.println(queue.take());
            System.out.println(queue.take());
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
        }
    }).start();
    
  • Механизми wait(), notify(), notifyAll(): Използват се за синхронизиране на нишки въз основа на монитори на обекти. Едно нишка извиква wait() за изчакване на условие, друго извиква notify() или notifyAll() за уведомяване на чакащите нишки за промяна на условието.
    // Използване на wait/notify
    class Data {
        private String message;
        private boolean empty = true;
    
        public synchronized String read() {
            while (empty) {
                try {
                    wait(); // Изчакване на данни
                } catch (InterruptedException e) {
                    Thread.currentThread().interrupt();
                }
            }
            empty = true;
            notifyAll(); // Уведомяване за възможност за писане
            return message;
        }
    
        public synchronized void write(String message) {
            while (!empty) {
                try {
                    wait(); // Изчакване, докато се прочетат предишните данни
                } catch (InterruptedException e) {
                    Thread.currentThread().interrupt();
                }
            }
            empty = false;
            this.message = message;
            notifyAll(); // Уведомяване за наличието на нови данни
        }
    }
    
  • CompletableFuture: Позволява създаване на асинхронни изчисления и обединяване на резултатите им, осигурявайки обмен на данни чрез връщаните стойности и обработчици за завършване.
  • Exchanger: Позволява на два потока да обменят обекти в точка на синхронизация.

Изборът на конкретен метод зависи от спецификата на задачата, необходимото ниво на синхронизация, производителността и сложността на реализация.