В этой статье рассмотрим CountDownLatch. В отличие от CyclicBarrier, где все потоки равноправны и ожидают друг друга, с CountDownLatch потоки делятся на два типа — одни уменьшают значение CountDownLatch, а другие ждут, когда он станет равен 0, чтобы продолжиться.
Рассмотрим пример. Допустим студенты выполняют тест и уходят домой (10 человек — 10 потоков), а учитель (1 поток) ждет, когда все сдадут тест, и потом продолжает работу.
Поток студента:
public class TestAndGo implements Runnable {
private CountDownLatch countDownLatch;
public TestAndGo(CountDownLatch countDownLatch) {
this.countDownLatch = countDownLatch;
}
@Override
public void run() {
System.out.println("в процессе тестирования");
countDownLatch.countDown();
System.out.println("пошел домой");
}
}
Как видите, тут фигурирует некий CountDownLatch, но на ход потока TestAndGo он не влияет никак — разве что у потока появляется маленькая дополнительная работа — команда
countDownLatch.countDown();
Она уменьшает значение счетчика на 1.
Сам же счетчик используется в другом потоке — потоке учителя (у нас это основной поток — метод main).
В нем мы запускаем 10 потоков TestAndGo и ждем, пока все студенты сдадут тест:
public static void main(String[] args) throws InterruptedException {
CountDownLatch countDownLatch=new CountDownLatch(10);
IntStream.range(0,10).forEach((i)->
new Thread(new TestAndGo(countDownLatch)).start());
countDownLatch.await();
System.out.println("все сдали, зачет окончен");
}
Ожидание выражается командой:
countDownLatch.await();
Главный поток останавливается в этом месте и и ждет до тех пор, пока countDownLatch не станет равным 0. Предварительно его создали со значением 10:
CountDownLatch countDownLatch=new CountDownLatch(10);
Таким образом, он станет равным 0, когда 10 потоков его уменьшат на 1 (это происходит после тестирования, но перед уходом домой). В итоге в консоли вывод такой (он может варьироваться, но главное, что строка «все сдали, зачет окончен» стоит после всех 10 выводов строки «в процессе тестирования»):
в процессе тестирования в процессе тестирования в процессе тестирования в процессе тестирования в процессе тестирования пошел домой пошел домой пошел домой в процессе тестирования пошел домой в процессе тестирования пошел домой пошел домой в процессе тестирования в процессе тестирования в процессе тестирования пошел домой все сдали, зачет окончен пошел домой пошел домой пошел домой
Учитель ждет, пока все студенты сдадут тест (при этом после сдачи теста студент не ждет, а идет домой). А сам учитель прекращает ожидание после того, как 10 тестов сданы (независимо от того, сколько студентов успело уйти домой, главное — сдача теста).
Если убрать команду countDownLatch.await(), то позиция строки «все сдали, зачет окончен» может быть любой.
Итоги
Мы рассмотрели CountDownLatch, код есть на GitHub. О CyclicBarrier читайте тут.