[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"question-mnogopotochnost-kak-podelitsya-dannymi-mezhdu-dvumya-potokami":3},{"id":4,"slug":5,"topicId":6,"topicSlug":7,"topicName":8,"topicEmoji":9,"question":10,"answer":11,"codeLang":12,"codeSrc":12,"important":12,"commonMistakes":12,"modernUsage":12,"difficulty":13,"tags":14,"related":20,"progress":21,"seo":22},270,"kak-podelitsya-dannymi-mezhdu-dvumya-potokami",8,"mnogopotochnost","Многопоточность","🔀","Как поделиться данными между двумя потоками?","\u003C!-- grade: 3\u002F5 — способы упомянуты, но не структурированы и нет примеров для большинства -->\n\nСуществует несколько способов передачи данных между потоками. Выбор зависит от паттерна взаимодействия.\n\n### 1. Общий объект с синхронизацией\n\nСамый простой способ -- потоки работают с одним и тем же объектом, доступ синхронизирован:\n\n```java\npublic class SharedData {\n    private String message;\n\n    public synchronized void setMessage(String msg) {\n        this.message = msg;\n        notify(); \u002F\u002F Уведомить ожидающий поток\n    }\n\n    public synchronized String getMessage() throws InterruptedException {\n        while (message == null) {\n            wait(); \u002F\u002F Ждать, пока данные не будут записаны\n        }\n        return message;\n    }\n}\n```\n\n### 2. BlockingQueue (производитель-потребитель)\n\nРекомендуемый способ для паттерна «производитель-потребитель»:\n\n\u003Cdetails>\n\u003Csummary>Пример: обмен через BlockingQueue\u003C\u002Fsummary>\n\n```java\nBlockingQueue\u003CString> queue = new LinkedBlockingQueue\u003C>(100);\n\n\u002F\u002F Производитель\nThread producer = new Thread(() -> {\n    try {\n        queue.put(\"Сообщение от производителя\");\n    } catch (InterruptedException e) {\n        Thread.currentThread().interrupt();\n    }\n});\n\n\u002F\u002F Потребитель\nThread consumer = new Thread(() -> {\n    try {\n        String msg = queue.take(); \u002F\u002F Блокируется, пока данные не появятся\n        System.out.println(\"Получено: \" + msg);\n    } catch (InterruptedException e) {\n        Thread.currentThread().interrupt();\n    }\n});\n\nproducer.start();\nconsumer.start();\n```\n\n\u003C\u002Fdetails>\n\n### 3. Exchanger (обмен между двумя потоками)\n\nКласс `Exchanger\u003CV>` предназначен для **двустороннего** обмена данными между ровно двумя потоками. Каждый поток вызывает `exchange()`, передаёт свои данные и получает данные другого потока:\n\n\u003Cdetails>\n\u003Csummary>Пример: обмен через Exchanger\u003C\u002Fsummary>\n\n```java\nExchanger\u003CString> exchanger = new Exchanger\u003C>();\n\nThread t1 = new Thread(() -> {\n    try {\n        String fromT2 = exchanger.exchange(\"Данные от T1\");\n        System.out.println(\"T1 получил: \" + fromT2);\n    } catch (InterruptedException e) {\n        Thread.currentThread().interrupt();\n    }\n});\n\nThread t2 = new Thread(() -> {\n    try {\n        String fromT1 = exchanger.exchange(\"Данные от T2\");\n        System.out.println(\"T2 получил: \" + fromT1);\n    } catch (InterruptedException e) {\n        Thread.currentThread().interrupt();\n    }\n});\n\nt1.start();\nt2.start();\n```\n\n\u003C\u002Fdetails>\n\n### 4. Concurrent-коллекции\n\nПотокобезопасные коллекции из `java.util.concurrent`:\n\n| Коллекция | Применение |\n|---|---|\n| `ConcurrentHashMap` | Конкурентное чтение\u002Fзапись ключ-значение |\n| `CopyOnWriteArrayList` | Редкая запись, частое чтение |\n| `ConcurrentLinkedQueue` | Неблокирующая очередь |\n\n### 5. Future \u002F CompletableFuture\n\nДля передачи **результата** из фонового потока в вызывающий:\n\n```java\nExecutorService executor = Executors.newSingleThreadExecutor();\nFuture\u003CString> future = executor.submit(() -> \"Результат вычисления\");\nString result = future.get(); \u002F\u002F Блокирует до получения результата\n```\n\n### 6. Pipe (PipedInputStream \u002F PipedOutputStream)\n\nДля потоковой передачи данных (редко используется, есть более удобные альтернативы):\n\n```java\nPipedOutputStream out = new PipedOutputStream();\nPipedInputStream in = new PipedInputStream(out);\n\u002F\u002F Один поток пишет в out, другой читает из in\n```\n\n### Сводная таблица\n\n| Способ | Паттерн | Блокировка | Направление |\n|---|---|---|---|\n| Общий объект + `synchronized` | Произвольный | Да | Двустороннее |\n| `BlockingQueue` | Производитель-потребитель | Да | Однонаправленное |\n| `Exchanger` | Обмен между парой потоков | Да | Двустороннее |\n| `CompletableFuture` | Асинхронный результат | Опционально | Однонаправленное |\n| Concurrent-коллекции | Конкурентный доступ | Частично | Двустороннее |\n\n> **Аналогия из жизни.** `BlockingQueue` -- это конвейерная лента на фабрике: один рабочий кладёт детали, другой забирает. `Exchanger` -- это рукопожатие с обменом документами: два человека встречаются, каждый отдаёт свой пакет и получает чужой. `Future` -- это квитанция: вы отдаёте задачу и потом приходите за результатом.\n\n> **На собеседовании.** Начните с `BlockingQueue` -- это самый распространённый и безопасный способ для паттерна «производитель-потребитель». Упомяните `Exchanger` -- его редко знают. Покажите, что знаете разницу между блокирующими и неблокирующими подходами. Также отметьте, что передача данных через общий объект без синхронизации -- это race condition.","","middle",[15,16,17,18,19],"BlockingQueue","обмен данными","Exchanger","общий объект","concurrency",[],null,{"title":23,"description":24,"ogTitle":25,"ogDescription":26,"keywords":27,"schemaAnswer":32,"featuredSnippetReady":33},"Обмен данными между потоками Java — BlockingQueue, Exchanger — Gymterview","Потоки обмениваются данными через общий объект, BlockingQueue или Exchanger. Exchanger блокирует поток до обмена данными с другим потоком.","Как поделиться данными между потоками?","Через общий объект, BlockingQueue или Exchanger. Exchanger.exchange() блокирует до момента обмена данными между двумя потоками.",[28,29,30,31],"обмен данными между потоками Java","BlockingQueue потоки","Exchanger Java","общий объект потоков","Через общий объект или параллельные структуры данных (BlockingQueue). Exchanger позволяет двум потокам обменяться данными: метод exchange() блокирует поток до момента, когда второй поток передаст свои данные.",true]