Вопрос, который зачастую дается в виде практической задачи. Конечно, результата можно добиться разными способами: парой
атомарных переменных,
критическими секциями,
потокобезопасными коллекциями. Но полезно знать, что специально для этого случая в стандартной библиотеке
java.util.concurrent есть простой класс
Exchanger.
Класс содержит единственный метод
V exchange(V x). Один поток передает в него данные, и встает в ожидание. Ожидание завершается, когда второй поток также приходит в метод exchange со своей порцией информации. В качестве результата вызова потоки получают данные друг друга.
На основе класса
Exchanger удобно создавать
пайплайны обработки данных. Первый поток выполняет свою часть обработки, и складывает результаты в буфер. В качестве буфера может работать любой многоразовый объект-контейнер. Когда он заполняется, следующий поток обменивает его на второй, пустой буфер. Таким образом два буфера используются поочередно, не выделяется лишний раз память и не нагружается
GC. Далее из попарно обменивающихся буферами потоков может строиться длинная многопоточная цепочка обработки.