CountDownLatch

В этой статье рассмотрим 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 читайте тут.

 

Добавить комментарий

Ваш адрес email не будет опубликован.