Счетчик ожидания в Java
CountDownLatch хранит счетчик событий.
Потоки вызывают countDown(), когда
закончили шаг, а другой поток ждет через
await(), пока счетчик не станет нулем.
Значение задают при создании и больше не увеличивают. После обнуления защелка не перезаряжается: для повторного цикла нужен новый экземпляр.
Главный поток ждет трех worker-ов:
import java.util.concurrent.CountDownLatch;
public class Main {
public static void main(String[] args) throws InterruptedException {
CountDownLatch ready = new CountDownLatch(3);
Runnable task = () -> {
try {
Thread.sleep(100);
System.out.println("done " + Thread.currentThread().getName());
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
} finally {
ready.countDown();
}
};
for (int i = 0; i < 3; i++) {
new Thread(task, "w" + i).start();
}
ready.await();
System.out.println("all finished");
}
}
Перегрузка await(long timeout, TimeUnit unit)
не ждет бесконечно. Метод getCount()
показывает, сколько сигналов еще не пришло:
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
public class Main {
public static void main(String[] args) throws InterruptedException {
CountDownLatch startLine = new CountDownLatch(1);
CountDownLatch done = new CountDownLatch(2);
Runnable runner = () -> {
try {
startLine.await();
System.out.println("go");
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
} finally {
done.countDown();
}
};
new Thread(runner).start();
new Thread(runner).start();
Thread.sleep(50);
startLine.countDown();
done.await(1, TimeUnit.SECONDS);
System.out.println("left: " + done.getCount());
}
}
CountDownLatch(4). Четыре потока
печатают метку и вызывают countDown().
Главный поток после await() выводит
"ready".