Класс CyclicBarrier
Класс CyclicBarrier представляет собой барьер синхронизации, который позволяет группе потоков ожидать достижения определенной точки. Когда все потоки достигнут барьера, они освобождаются и могут продолжить выполнение. Особенность данного барьера заключается в том, что его можно использовать повторно (циклически) после сброса. В конструктор класса мы передаем количество потоков, которые должны достичь барьера. Также можно передать необязательный параметр - реализацию Runnable, которая выполнится один раз в момент пересечения барьера.
Синтаксис
CyclicBarrier barrier = new CyclicBarrier(parties);
CyclicBarrier barrier = new CyclicBarrier(parties, barrierAction);
Основные методы
Класс предоставляет следующие основные методы:
int await() // ожидает прибытия всех потоков
int await(long timeout, TimeUnit unit) // ожидает с таймаутом
int getParties() // возвращает количество сторон
int getNumberWaiting() // возвращает количество ожидающих
boolean isBroken() // проверяет, сломан ли барьер
void reset() // сбрасывает барьер
Пример
Давайте создадим барьер для 3 потоков и посмотрим, как они синхронизируются:
import java.util.concurrent.CyclicBarrier;
public class Main
{
public static void main(String[] args)
{
CyclicBarrier barrier = new CyclicBarrier(3, () -> {
System.out.println("Барьер пройден!");
});
for (int i = 0; i < 3; i++) {
final int threadNum = i;
new Thread(() -> {
try {
System.out.println("Поток " + threadNum + " достиг барьера");
barrier.await();
System.out.println("Поток " + threadNum + " продолжил работу");
} catch (Exception e) {
e.printStackTrace();
}
}).start();
}
}
}
Результат выполнения кода:
"Поток 0 достиг барьера"
"Поток 2 достиг барьера"
"Поток 1 достиг барьера"
"Барьер пройден!"
"Поток 1 продолжил работу"
"Поток 0 продолжил работу"
"Поток 2 продолжил работу"
Пример
Давайте рассмотрим повторное использование барьера после его сброса:
import java.util.concurrent.CyclicBarrier;
public class Main
{
public static void main(String[] args)
{
CyclicBarrier barrier = new CyclicBarrier(2);
Runnable task = () -> {
try {
System.out.println(Thread.currentThread().getName() + " ждет");
barrier.await();
System.out.println(Thread.currentThread().getName() + " пошел");
} catch (Exception e) {
e.printStackTrace();
}
};
new Thread(task, "A").start();
new Thread(task, "B").start();
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("Барьер сброшен");
barrier.reset();
}
}
Результат выполнения кода:
"A ждет"
"B ждет"
"A пошел"
"B пошел"
"Барьер сброшен"
Смотрите также
-
класс
CountDownLatch,
который также синхронизирует потоки -
класс
Semaphore,
который управляет доступом к ресурсам -
класс
ReentrantLock,
который предоставляет блокировки -
класс
TimeUnit,
который используется для таймаутов