Иногда требуется, чтобы поток исполнения находился в режиме ожидания до тех пор, пока не наступит одно (или больше) событие.
Для этих целей в параллельном API предоставляется класс CountDownLatch, реализующий самоблокировку с обратным отсчетом. Объект этого класса изначально создается с количеством событий, которые должны произойти до того момента, как будет снята самоблокировка. Всякий раз, когда происходит событие, значение счетчика уменьшается.
Как только значение счетчика достигнет нуля, самоблокировка будет снята.
В классе CountDownLatch имеется приведенный ниже конструктор, где параметр число определяет количество событий, которые должны произойти до того, как будет снята самоблокировка.
1 |
CountDownLatch(int число) |
Для ожидания по самоблокировке в потоке исполнения вызывается метод await(), общие формы которого приведены ниже.
1 2 |
void await() throws InterruptedException boolean await(long ожидание, TimeUnit единица_времени) throws InterruptedException |
В первой форме ожидание длится до тех пор, пока отсчет, связанный с вызывающим объектом типа CountDownLatch, не достигнет нуля. А во второй форме ожидание длится только в течение определенного периода времени, определяемого параметром ожидание.
Время ожидания указывается в единицах, обозначаемых параметром единица_времени, который принимает объект перечисления TimeUnit.
Метод await() возвращает логическое значение false, если достигнут предел времени ожидания, или логическое значение true, если обратный отсчет достигает нуля.
Чтобы известить о событии, следует вызвать метод countDown(). Ниже приведена общая форма этого метода. Всякий раз, когда вызывается метод countDown(), отсчет, связанный с вызывающим объектом, уменьшается на единицу.
1 |
void countDown() |
В приведенном ниже примере программы демонстрируется применение класса CountDownLatch. В этой программе устанавливается самоблокировка, которая снимается только после наступления пяти событий.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 |
// Продемонстрируем применение класса CountDownLatch import java.util.concurrent.CountDownLatch; class CDLDemo { public static void main(String args[]) { CountDownLatch cdl = new CountDownLatch(5); System.out.println("Запуск потока исполнения"); new MyThread(cdl); try { cdl.await(); } catch (InterruptedException exc) { System.out.println(exc); } System.out.println("Завершение потока исполнения"); } } class MyThread implements Runnable { CountDownLatch latch; MyThread(CountDownLatch c) { latch = c; new Thread(this).start(); } public void run() { for(int i = 0; i < 5; i++) { System.out.println(i); latch.countDown(); // обратный отсчет } } |
Ниже приведен результат выполнения данной программы:
1 2 3 4 5 6 7 |
Запуск потока исполнения 0 1 2 3 4 Завершение потока исполнения |
В теле метода mаin() устанавливается самоблокировка в виде объекта cdl типа CountDownLatch с исходным значением обратного отсчета, равным 5.
Затем создается экземпляр класса MyThread, который начинает исполнение нового потока. Обратите внимание на то, что объект cdl передается в качестве параметра конструктору класса MyThread и сохраняется в переменной экземпляра latch.
Далее в главном потоке исполнения вызывается метод await() для объекта cdl, в результате чего исполнение главного потока приостанавливается до тех пор. пока обратный отсчет самоблокировки не уменьшится на единицу пять раз в объекте cdl.
В теле метода run() из класса MyThread организуется цикл, который повторяется пять раз. На каждом шаге этого цикла вызывается метод countDown() для переменной экземпляра latch, которая ссылается на объект cdl в методе main(). По завершении пятого шага цикла самоблокировка снимается, позволяя возобновить главный поток исполнения.
Класс CountDownLatch является эффективным и простым в употреблении средством синхронизации, которое окажется полезным в тех случаях, когда поток исполнения должен находиться в состоянии ожидания до тех пор, пока не произойдет одно или несколько событий.