Может ли кто-нибудь помочь мне понять, что такое Java CountDownLatch
и когда его использовать?
У меня нет четкого представления о том, как работает эта программа. Как я понимаю, все три потока запускаются одновременно, и каждый поток вызовет CountDownLatch через 3000 мс. Так что обратный отсчет будет уменьшаться один за другим. После того, как защелка станет нулевой, программа напечатает «Завершено». Может быть, то, как я понял, неверно.
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
class Processor implements Runnable {
private CountDownLatch latch;
public Processor(CountDownLatch latch) {
this.latch = latch;
}
public void run() {
System.out.println("Started.");
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
latch.countDown();
}
}
// ------------------------------------------------ -----
public class App {
public static void main(String[] args) {
CountDownLatch latch = new CountDownLatch(3); // coundown from 3 to 0
ExecutorService executor = Executors.newFixedThreadPool(3); // 3 Threads in pool
for(int i=0; i < 3; i++) {
executor.submit(new Processor(latch)); // ref to latch. each time call new Processes latch will count down by 1
}
try {
latch.await(); // wait until latch counted down to 0
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("Completed.");
}
}
Ответы:
Да, вы правильно поняли.
CountDownLatch
работает по принципу защелки, основной поток будет ждать, пока ворота не откроются. Один поток ожидает n потоков, указанных при созданииCountDownLatch
.Любой поток, обычно основной поток приложения, вызов которого
CountDownLatch.await()
будет ожидать, пока счетчик не достигнет нуля или не прервется другим потоком. Все остальные потоки обязаны вести обратный отсчет, вызывая их,CountDownLatch.countDown()
когда они завершены или готовы.Как только счет достигает нуля, ожидающий поток продолжается. Одним из недостатков / преимуществ
CountDownLatch
является то, что его нельзя использовать повторно: как только счет достигнет нуля, вы больше не сможете его использоватьCountDownLatch
.Редактировать:
Используется,
CountDownLatch
когда одному потоку (например, основному потоку) требуется дождаться завершения одного или нескольких потоков, прежде чем он сможет продолжить обработку.Классическим примером использования
CountDownLatch
в Java является базовое Java-приложение на стороне сервера, которое использует архитектуру служб, где несколько служб предоставляются несколькими потоками, и приложение не может начать обработку, пока все службы не будут успешно запущены.У вопроса PS OP довольно простой пример, поэтому я его не включил.
источник
One thread waits for n number of threads specified while creating CountDownLatch in Java
. Если вам нужен такой механизм, то его целесообразно использоватьCyclicBarrier
. Фундаментальное концептуальное различие между этими двумя, как указано вJava concurrency in Practice
это:Latches are for waiting for events; barriers are for waiting for other threads
.cyclicBarrier.await()
переходит в состояние блокировкиCountDownLatch
в Java это тип синхронизатора, который позволяетThread
подождать один или несколькоThread
секунд, прежде чем он начнет обработку.CountDownLatch
работает по принципу защелки, поток будет ждать, пока ворота не откроются. Один поток ожидаетn
количество потоков, указанное при созданииCountDownLatch
.например
final CountDownLatch latch = new CountDownLatch(3);
Здесь мы устанавливаем счетчик на 3.
Любой поток, обычно основной поток приложения, вызов которого
CountDownLatch.await()
будет ожидать, пока счетчик не достигнет нуля или не прервется другимThread
. Все остальные потоки обязаны выполнять обратный отсчет путем вызоваCountDownLatch.countDown()
после завершения или готовности к работе. как только счет достигает нуля,Thread
запускается ожидание.Здесь счетчик уменьшается по
CountDownLatch.countDown()
методу.Метод,
Thread
который вызываетawait()
метод, будет ждать, пока начальное число не достигнет нуля.Чтобы счетчик равнялся нулю, другие потоки должны вызывать
countDown()
метод. Как только счет станет равным нулю, поток, вызвавшийawait()
метод, возобновит работу (начнет его выполнение).Недостатком
CountDownLatch
является то, что он не может быть использован повторно: как только счет станет равным нулю, он больше не будет использоваться.источник
new CountDownLatch(3)
как у нас есть 3 потока изnewFixedThreadPool
определенного?NikolaB объяснил это очень хорошо, однако пример будет полезен для понимания, так что вот один простой пример ...
источник
Он используется, когда мы хотим подождать, пока несколько потоков выполнят свою задачу. Это похоже на присоединение к темам.
Где мы можем использовать CountDownLatch
Рассмотрим сценарий, где у нас есть требование, когда у нас есть три потока «A», «B» и «C», и мы хотим запустить поток «C» только тогда, когда потоки «A» и «B» завершают или частично завершают свою задачу.
Это может быть применено к реальному сценарию IT
Рассмотрим сценарий, в котором менеджер разделяет модули между группами разработчиков (A и B) и хочет назначить их команде QA для тестирования только тогда, когда обе команды выполнят свою задачу.
Вывод вышеуказанного кода будет:
Задача, поставленная перед командой разработчиков devB
Задача, поставленная перед командой разработчиков devA
Задача выполнена командой разработчиков devB
Задача выполнена командой разработчиков devA
Задача, назначенная команде QA
Задача выполнена командой QA
Здесь метод await () ожидает, когда флаг countdownlatch станет равным 0, а метод countDown () уменьшает флаг countdownlatch на 1.
Ограничение JOIN: Приведенный выше пример также может быть достигнут с помощью JOIN, но JOIN нельзя использовать в двух сценариях:
источник
CoundDownLatch позволяет вам заставить поток ждать, пока все остальные потоки не завершат свое выполнение.
Псевдокод может быть:
источник
Один хороший пример того, когда использовать что-то подобное, - это Java Simple Serial Connector для доступа к последовательным портам. Обычно вы что-то записываете в порт, и асинхронно в другом потоке устройство отвечает SerialPortEventListener. Как правило, вы хотите сделать паузу после записи в порт, чтобы дождаться ответа. Ручная обработка потоков для этого сценария чрезвычайно сложна, но использовать Countdownlatch легко. Прежде чем думать, что вы можете сделать это по-другому, будьте осторожны с условиями гонки, о которых вы никогда не думали !!
псевдокод:
источник
Если вы добавите отладку после вызова latch.countDown (), это может помочь вам лучше понять ее поведение.
Выходные данные покажут, что число уменьшается. Это 'count' - это фактически число запущенных задач (объектов Processor), для которых вы начали, countDown () не был вызван и, следовательно, блокируется основным потоком при вызове latch.await ().
источник
Из документации оракула о CountDownLatch :
А
CountDownLatch
инициализируется с заданным количеством. Этиawait
методы блокируют до тех пор , текущее значение счетчика достигает нуля не связано с вызовамиcountDown()
метода, после чего все потоки , ожидающие будут освобождены и любых последующих вызовах ждать возвращения немедленно. Это одноразовое явление - счет не может быть сброшен.CountDownLatch
Инициализируется со счетчиком одного служит простой вкл / выкл, защелка или ворот: для всех потоков , ссылающимся ждут ждать в воротах , пока не будет открыт с помощью резьбы вызова CountDown ().CountDownLatch
Инициализируется N может быть использован , чтобы сделать одну нить ждать , пока N потоков не выполнили какое - либо действие, или какое - то действие было завершено N раз.Если текущий счетчик равен нулю, этот метод возвращается немедленно.
Если текущий счетчик больше нуля, то он уменьшается. Если новый счетчик равен нулю, то все ожидающие потоки повторно включаются для целей планирования потоков.
Объяснение вашего примера.
Вы установили счетчик как 3 для
latch
переменнойВы передали этот общий ресурс
latch
в рабочий поток:Processor
Runnable
экземпляраProcessor
были представленыExecutorService
executor
Основной поток (
App
) ожидает, что число станет нулевым с оператором нижеProcessor
поток спит в течение 3 секунд, а затем уменьшает значение счетчика сlatch.countDown()
Первый
Process
экземпляр изменит количество защелок на 2 после его завершения из-заlatch.countDown()
.Второй
Process
экземпляр изменит количество защелок на 1 после его завершения из-заlatch.countDown()
.Третий
Process
экземпляр изменит количество защелок на 0 после его завершения из-заlatch.countDown()
.Нулевой отсчет на защелке приводит к тому, что основной поток
App
выходит изawait
Приложение App теперь печатает этот вывод:
Completed
источник
Этот пример из Java Doc помог мне понять концепции:
Визуальная интерпретация:
Очевидно,
CountDownLatch
позволяет одному потоку (здесьDriver
) ждать, пока несколько запущенных потоков (здесьWorker
) не завершат их выполнение.источник
Как упоминалось в JavaDoc ( https://docs.oracle.com/javase/7/docs/api/java/util/concurrent/CountDownLatch.html ), CountDownLatch - это средство синхронизации, представленное в Java 5. Здесь синхронизация не означает ограничение доступа к критическому разделу. Но скорее последовательность действий разных потоков. Тип синхронизации, достигнутый с помощью CountDownLatch, аналогичен типу Join. Предположим, что существует поток «M», который должен ждать, пока другие рабочие потоки «T1», «T2», «T3» завершат свои задачи. До Java 1.5 это можно было сделать следующим образом: M выполняет следующий код
Приведенный выше код гарантирует, что поток M возобновит свою работу после того, как T1, T2, T3 завершат свою работу. T1, T2, T3 могут завершить свою работу в любом порядке. То же самое может быть достигнуто с помощью CountDownLatch, где T1, T2, T3 и поток M совместно используют один и тот же объект CountDownLatch.
«M» запрашивает:
countDownLatch.await();
где, как «T1», «T2», «T3» делает
countDownLatch.countdown();
Недостатком метода соединения является то, что М должен знать о T1, T2, T3. Если позже добавлен новый рабочий поток T4, то M тоже должен об этом знать. Этого можно избежать с помощью CountDownLatch. После реализации последовательность действий будет [T1, T2, T3] (порядок T1, T2, T3 может быть в любом случае) -> [M]
источник
Лучший пример реального времени для countDownLatch, объясненный в этой ссылке CountDownLatchExample
источник
источник