Ответ 1
Да, "t.join()" делает текущий поток, ожидающий поток "t", завершен, и мы можем подготовить цепочку потоков, когда поток ждет какой-то другой. Но иногда CountDownLatch/CyclicBarrier более удобны.
Прежде всего, CountDownLatch/CyclicBarrier не требует, чтобы все рабочие потоки были закончены. Потоки могут выполняться все время работы приложения. Они просто позволяют нам сказать, что "некоторая работа" выполняется несколько раз. Более того, если у нас есть N заданий и M потоков и N > M, некоторые потоки могут выполнять задание несколько раз, пока их общий бариер N не равен 0. Этот пример показывает, что CountDownLatch/CyclicBarrier - очень полезные примитивы для совместного использования N задач между M потоками.
Кроме того, чтобы использовать join(), каждый поток должен иметь ссылку на другой поток для вызова join(). Это делает ваш код немного грязным, особенно если у вас более двух рабочих потоков. Общий доступ к одному экземпляру CountDownLatch/CyclicBarrier выглядит более понятным.
Основное различие между CyclicBarrier и CountDownLatch заключается в том, что CyclicBarrier многократно используется, а CountDownLatch - нет. Вы можете повторно использовать CyclicBarrier, вызвав метод reset(), который сбрасывает барьер в исходное состояние.
CountDownLatch хорош для одноразового события, такого как время запуска приложения/модуля, и CyclicBarrier может использоваться в случае повторного события, например. одновременно (пересчитывать) каждый раз при изменении входных данных.
Вы можете найти несколько хороших примеров:
http://javarevisited.blogspot.sg/2012/07/countdownlatch-example-in-java.html http://javarevisited.blogspot.ru/2012/07/cyclicbarrier-example-java-5-concurrency-tutorial.html