Polytech-soft.com

ПК журнал
3 просмотров
Рейтинг статьи
1 звезда2 звезды3 звезды4 звезды5 звезд
Загрузка...

Countdownlatch java пример

Справочник по синхронизаторам java.util.concurrent.*

Целью данной публикации не является полный анализ синхронизаторов из пакета java.util.concurrent. Пишу её, прежде всего, как справочник, который облегчит вхождение в тему и покажет возможности практического применения классов для синхронизации потоков (далее поток = thread).

В java.util.concurrent много различных классов, которые по функционалу можно поделить на группы: Concurrent Collections, Executors, Atomics и т.д. Одной из этих групп будет Synchronizers (синхронизаторы).

Синхронизаторы – вспомогательные утилиты для синхронизации потоков, которые дают возможность разработчику регулировать и/или ограничивать работу потоков и предоставляют более высокий уровень абстракции, чем основные примитивы языка (мониторы).

Semaphore

Синхронизатор Semaphore реализует шаблон синхронизации Семафор. Чаще всего, семафоры необходимы, когда нужно ограничить доступ к некоторому общему ресурсу. В конструктор этого класса ( Semaphore(int permits) или Semaphore(int permits, boolean fair) ) обязательно передается количество потоков, которому семафор будет разрешать одновременно использовать заданный ресурс.

Доступ управляется с помощью счётчика: изначально значение счётчика равно int permits , когда поток заходит в заданный блок кода, то значение счётчика уменьшается на единицу, когда поток его покидает, то увеличивается. Если значение счётчика равно нулю, то текущий поток блокируется, пока кто-нибудь не выйдет из блока (в качестве примера из жизни с permits = 1 , можно привести очередь в кабинет в поликлинике: когда пациент покидает кабинет, мигает лампа, и заходит следующий пациент).

Рассмотрим следующий пример. Существует парковка, которая одновременно может вмещать не более 5 автомобилей. Если парковка заполнена полностью, то вновь прибывший автомобиль должен подождать пока не освободится хотя бы одно место. После этого он сможет припарковаться.

CountDownLatch

CountDownLatch (замок с обратным отсчетом) предоставляет возможность любому количеству потоков в блоке кода ожидать до тех пор, пока не завершится определенное количество операций, выполняющихся в других потоках, перед тем как они будут «отпущены», чтобы продолжить свою деятельность. В конструктор CountDownLatch ( CountDownLatch(int count) ) обязательно передается количество операций, которое должно быть выполнено, чтобы замок «отпустил» заблокированные потоки.

Блокировка потоков снимается с помощью счётчика: любой действующий поток, при выполнении определенной операции уменьшает значение счётчика. Когда счётчик достигает 0, все ожидающие потоки разблокируются и продолжают выполняться (примером CountDownLatch из жизни может служить сбор экскурсионной группы: пока не наберется определенное количество человек, экскурсия не начнется).

Рассмотрим следующий пример. Мы хотим провести автомобильную гонку. В гонке принимают участие пять автомобилей. Для начала гонки нужно, чтобы выполнились следующие условия:

  1. Каждый из пяти автомобилей подъехал к стартовой прямой;
  2. Была дана команда «На старт!»;
  3. Была дана команда «Внимание!»;
  4. Была дана команда «Марш!».

Важно, чтобы все автомобили стартовали одновременно.

CyclicBarrier

CyclicBarrier реализует шаблон синхронизации Барьер. Циклический барьер является точкой синхронизации, в которой указанное количество параллельных потоков встречается и блокируется. Как только все потоки прибыли, выполняется опционное действие (или не выполняется, если барьер был инициализирован без него), и, после того, как оно выполнено, барьер ломается и ожидающие потоки «освобождаются». В конструктор барьера ( CyclicBarrier(int parties) и CyclicBarrier(int parties, Runnable barrierAction) ) обязательно передается количество сторон, которые должны «встретиться», и, опционально, действие, которое должно произойти, когда стороны встретились, но перед тем когда они будут «отпущены».

Барьер похож на CountDownLatch, но главное различие между ними в том, что вы не можете заново использовать «замок» после того, как его счётчик достигнет нуля, а барьер вы можете использовать снова, даже после того, как он сломается. CyclicBarrier является альтернативой метода join() , который «собирает» потоки только после того, как они выполнились.

Рассмотрим следующий пример. Существует паромная переправа. Паром может переправлять одновременно по три автомобиля. Чтобы не гонять паром лишний раз, нужно отправлять его, когда у переправы соберется минимум три автомобиля.

Exchanger

Exchanger (обменник) может понадобиться, для того, чтобы обменяться данными между двумя потоками в определенной точки работы обоих потоков. Обменник — обобщенный класс, он параметризируется типом объекта для передачи.

Обменник является точкой синхронизации пары потоков: поток, вызывающий у обменника метод exchange() блокируется и ждет другой поток. Когда другой поток вызовет тот же метод, произойдет обмен объектами: каждая из них получит аргумент другой в методе exchange() . Стоит отметить, что обменник поддерживает передачу null значения. Это дает возможность использовать его для передачи объекта в одну сторону, или, просто как точку синхронизации двух потоков.

Рассмотрим следующий пример. Есть два грузовика: один едет из пункта A в пункт D, другой из пункта B в пункт С. Дороги AD и BC пересекаются в пункте E. Из пунктов A и B нужно доставить посылки в пункты C и D. Для этого грузовики в пункте E должны встретиться и обменяться соответствующими посылками.

Phaser

Phaser (фазер), как и CyclicBarrier, является реализацией шаблона синхронизации Барьер, но, в отличии от CyclicBarrier, предоставляет больше гибкости. Этот класс позволяет синхронизировать потоки, представляющие отдельную фазу или стадию выполнения общего действия. Как и CyclicBarrier, Phaser является точкой синхронизации, в которой встречаются потоки-участники. Когда все стороны прибыли, Phaser переходит к следующей фазе и снова ожидает ее завершения.

Читать еще:  Java логические операторы

Если сравнить Phaser и CyclicBarrier, то можно выделить следующие важные особенности Phaser:

  • Каждая фаза (цикл синхронизации) имеет номер;
  • Количество сторон-участников жестко не задано и может меняться: поток может регистрироваться в качестве участника и отменять свое участие;
  • Участник не обязан ожидать, пока все остальные участники соберутся на барьере. Чтобы продолжить свою работу достаточно сообщить о своем прибытии;
  • Случайные свидетели могут следить за активностью в барьере;
  • Поток может и не быть стороной-участником барьера, чтобы ожидать его преодоления;
  • У фазера нет опционального действия.

Объект Phaser создается с помощью одного из конструкторов:

Параметр parties указывает на количество сторон-участников, которые будут выполнять фазы действия. Первый конструктор создает объект Phaser без каких-либо сторон, при этом барьер в этом случае тоже «закрыт». Второй конструктор регистрирует передаваемое в конструктор количество сторон. Барьер открывается когда все стороны прибыли, или, если снимается последний участник. (У класса Phaser еще есть конструкторы, в которые передается родительский объект Phaser, но мы их рассматривать не будем.)

Основные методы:

  • int register() — регистрирует нового участника, который выполняет фазы. Возвращает номер текущей фазы;
  • int getPhase() — возвращает номер текущей фазы;
  • int arriveAndAwaitAdvance() — указывает что поток завершил выполнение фазы. Поток приостанавливается до момента, пока все остальные стороны не закончат выполнять данную фазу. Точный аналог CyclicBarrier.await() . Возвращает номер текущей фазы;
  • int arrive() — сообщает, что сторона завершила фазу, и возвращает номер фазы. При вызове данного метода поток не приостанавливается, а продолжает выполнятся;
  • int arriveAndDeregister() — сообщает о завершении всех фаз стороной и снимает ее с регистрации. Возвращает номер текущей фазы;
  • int awaitAdvance(int phase) — если phase равно номеру текущей фазы, приостанавливает вызвавший его поток до её окончания. В противном случае сразу возвращает аргумент.


Официальная документация по Phaser.

Рассмотрим следующий пример. Есть пять остановок. На первых четырех из них могут стоять пассажиры и ждать автобуса. Автобус выезжает из парка и останавливается на каждой остановке на некоторое время. После конечной остановки автобус едет в парк. Нам нужно забрать пассажиров и высадить их на нужных остановках.

Если кому-нибудь пригодилось, то я очень рад=)

Более подробно о Phaser здесь.
Почитать ещё о синхронизаторах и посмотреть примеры можно здесь.

Блог только про Java

Учимся программировать на Java с нуля

Класс CountDownLatch, примеры реализации кода в Java

Иногда требуется, чтобы поток исполнения находился в режиме ожидания до тех пор, пока не наступит одно (или больше) событие.

Для этих целей в парал­лельном API предоставляется класс CountDownLatch, реализующий самоблокировку с обратным отсчетом. Объект этого класса изначально создается с количеством событий, которые должны произойти до того момента, как будет снята самоблокировка. Всякий раз, когда происходит событие, значение счетчика уменьшается.

Как только значение счетчика достигнет нуля, самоблокировка будет снята.

В классе CountDownLatch имеется приведенный ниже конструктор, где пара­метр число определяет количество событий, которые должны произойти до того, как будет снята самоблокировка.

Для ожидания по самоблокировке в потоке исполнения вызывается метод await(), общие формы которого приведены ниже.

В первой форме ожидание длится до тех пор, пока отсчет, связанный с вызы­вающим объектом типа CountDownLatch, не достигнет нуля. А во второй форме ожидание длится только в течение определенного периода времени, определяе­мого параметром ожидание.

Время ожидания указывается в единицах, обозначаемых параметром единица_времени, который принимает объект перечисления TimeUnit.

Метод await() возвращает ло­гическое значение false, если достигнут предел времени ожидания, или логиче­ское значение true, если обратный отсчет достигает нуля.

Чтобы известить о событии, следует вызвать метод countDown(). Ниже при­ведена общая форма этого метода. Всякий раз, когда вызывается метод countDown(), отсчет, связанный с вызывающим объектом, уменьшается на единицу.

В приведенном ниже примере программы демонстрируется применение клас­са CountDownLatch. В этой программе устанавливается самоблокировка, которая снимается только после наступления пяти событий.

Ниже приведен результат выполнения данной программы:

В теле метода mаin() устанавливается самоблокировка в виде объекта cdl типа CountDownLatch с исходным значением обратного отсчета, равным 5.

Затем соз­дается экземпляр класса MyThread, который начинает исполнение нового потока. Обратите внимание на то, что объект cdl передается в качестве параметра кон­структору класса MyThread и сохраняется в переменной экземпляра latch.

Далее в главном потоке исполнения вызывается метод await() для объекта cdl, в резуль­тате чего исполнение главного потока приостанавливается до тех пор. пока обратный отсчет самоблокировки не уменьшится на единицу пять раз в объекте cdl.

В теле метода run() из класса MyThread организуется цикл, который повторяется пять раз. На каждом шаге этого цикла вызывается метод countDown() для пе­ременной экземпляра latch, которая ссылается на объект cdl в методе main(). По завершении пятого шага цикла самоблокировка снимается, позволяя возобно­вить главный поток исполнения.

Читать еще:  Восстановление запуска windows 10 из командной строки

Класс CountDownLatch является эффективным и простым в употреблении средством синхронизации, которое окажется полезным в тех случаях, когда поток исполнения должен находиться в состоянии ожидания до тех пор, пока не произойдет одно или несколько событий.

Советуем вам следующее интересное видео:

Gu >Last modified: May 12, 2019

I just announced the new Learn Spring course, focused on the fundamentals of Spring 5 and Spring Boot 2:

In the 9 years of running Baeldung, I’ve never, ever done a «sale».
But. we’ve also not been through anything like this pandemic either.
And, if making my courses more affordable for a while is going to help a company stay in business, or a developer land a new job, make rent or be able to provide for their family — then it’s well worth doing.
Effective immediately, all Baeldung courses are 33% off their normal prices!
You’ll find all three courses in the menu, above, or here.

1. Introduction

In this article, we’ll give a guide to the CountDownLatch class and demonstrate how it can be used in a few practical examples.

Essentially, by using a CountDownLatch we can cause a thread to block until other threads have completed a given task.

2. Usage in Concurrent Programming

Simply put, a CountDownLatch has a counter field, which you can decrement as we require. We can then use it to block a calling thread until it’s been counted down to zero.

If we were doing some parallel processing, we could instantiate the CountDownLatch with the same value for the counter as a number of threads we want to work across. Then, we could just call countdown() after each thread finishes, guaranteeing that a dependent thread calling await() will block until the worker threads are finished.

3. Waiting for a Pool of Threads to Complete

Let’s try out this pattern by creating a Worker and using a CountDownLatch field to signal when it has completed:

Then, let’s create a test in order to prove that we can get a CountDownLatch to wait for the Worker instances to complete:

Naturally “Latch released” will always be the last output – as it’s dependant on the CountDownLatch releasing.

Note that if we didn’t call await(), we wouldn’t be able to guarantee the ordering of the execution of the threads, so the test would randomly fail.

4. A Pool of Threads Waiting to Begin

If we took the previous example, but this time started thousands of threads instead of five, it’s likely that many of the earlier ones will have finished processing before we have even called start() on the later ones. This could make it difficult to try and reproduce a concurrency problem, as we wouldn’t be able to get all our threads to run in parallel.

To get around this, let’s get the CountdownLatch to work differently than in the previous example. Instead of blocking a parent thread until some child threads have finished, we can block each child thread until all the others have started.

Let’s modify our run() method so it blocks before processing:

Now, let’s modify our test so it blocks until all the Workers have started, unblocks the Workers, and then blocks until the Workers have finished:

This pattern is really useful for trying to reproduce concurrency bugs, as can be used to force thousands of threads to try and perform some logic in parallel.

5. Terminating a CountdownLatch Early

Sometimes, we may run into a situation where the Workers terminate in error before counting down the CountDownLatch. This could result in it never reaching zero and await() never terminating:

Let’s modify our earlier test to use a BrokenWorker, in order to show how await() will block forever:

Clearly, this is not the behavior we want – it would be much better for the application to continue than infinitely block.

To get around this, let’s add a timeout argument to our call to await().

As we can see, the test will eventually time out and await() will return false.

6. Conclusion

In this quick guide, we’ve demonstrated how we can use a CountDownLatch in order to block a thread until other threads have finished some processing.

We’ve also shown how it can be used to help debug concurrency issues by making sure threads run in parallel.

Читать еще:  Двухмерные массивы java

The implementation of these examples can be found over on GitHub; this is a Maven-based project, so should be easy to run as is.

Java concurrency – CountDownLatch Example

By Lokesh Gupta | Filed Under: Java Concurrency

As per java docs, CountDownLatch is a synchronization aid that allows one or more threads to wait until a set of operations being performed in other threads completes. CountDownLatch concept is very common interview question in java concurrency, so make sure you understand it well. In this post, I will cover following points related to CountDownLatch in java concurrency.

What is CountDownLatch?

CountDownLatch was introduced with JDK 1.5 along with other concurrent utilities like CyclicBarrier, Semaphore, ConcurrentHashMap and BlockingQueue in java.util.concurrent package. This class enables a java thread to wait until other set of threads completes their tasks. e.g. Application’s main thread want to wait, till other service threads which are responsible for starting framework services have completed started all services.

CountDownLatch works by having a counter initialized with number of threads, which is decremented each time a thread complete its execution. When count reaches to zero, it means all threads have completed their execution, and thread waiting on latch resume the execution.

CountDownLatch Concept

Pseudo code for CountDownLatch can be written like this:

How CountDownLatch works?

CountDownLatch.java class defines one constructor inside:

This count is essentially the number of threads, for which latch should wait. This value can be set only once, and CountDownLatch provides no other mechanism to reset this count.

The first interaction with CountDownLatch is with main thread which is goind to wait for other threads. This main thread must call, CountDownLatch.await() method immediately after starting other threads. The execution will stop on await() method till the time, other threads complete their execution.

Other N threads must have reference of latch object, because they will need to notify the CountDownLatch object that they have completed their task. This notification is done by method : CountDownLatch.countDown(); Each invocation of method decreases the initial count set in constructor, by 1. So, when all N threads have call this method, count reaches to zero, and main thread is allowed to resume its execution past await() method.

Possible usages in real time applications

Let’s try to identify some possible usage of CountDownLatch in real time java applications. I am listing, as much i can recall. If you have any other possible usage, please leave a comment. It will help others.

  1. Achieving Maximum Parallelism : Sometimes we want to start a number of threads at the same time to achieve maximum parallelism. For example, we want to test a class for being singleton. This can be done easily if we create a CountDownLatch with initial count 1, and make wait all threads to wait of latch. A single call to countDown() method will resume execution for all waiting threads in same time.
  2. Wait N threads to completes before start execution: For example an application start-up class want to ensure that all N external systems are Up and running before handling the user requests.
  3. Deadlock detection: A very handy use case in which you can use N threads to access a shared resource with different number of threads in each test phase, and try to create a deadlock.

Example application using CountDownLatch

In this example, I have simulated an application startup class which starts N threads that will check for external systems and report back to latch, on which startup class is waiting. As soon as all services are verified and checked, startup proceeds.

BaseHealthChecker.java : This class is a Runnable and parent for all specific external service health checkers. This remove the code duplicacy and central control over latch.

NetworkHealthChecker.java : This class extends BaseHealthChecker and needs to provide only implementation of verifyService() method. DatabaseHealthChecker.java and CacheHealthChecker.java are same as NetworkHealthChecker.java apart from their service names and sleep time.

ApplicationStartupUtil.java : This clas is main startup class which initilizes the latch and wait of this latch till all services are checked.

Now you can write any test class to check the functionality of latch.

Common interview questions

Be prepared to face these questions related to CountDownLatch in your next interview.

  • Explain the concept of CountDownLatch?
  • Difference between CountDownLatch and CyclicBarrier?
  • Give some example uses of CountDownLatch?
  • What are main methods CountDownLatch class has?

To Download the sourcecode of above example application follow given link.

Ссылка на основную публикацию
Adblock
detector