В этом разделе приведено немало примеров использования различных компонентов. Другие, относительно редко встречающиеся компоненты, здесь не рассматриваются.
Так как компоненты предназначены для решения разных проблем, простого способа их упорядочения не существует, поэтому мы начнем с более простых примеров и постепенно перейдем к более сложным.
CountDownLatch
Класс синхронизирует задачи, заставляя их ожидать завершения группы операций, выполняемых другими задачами.
Объекту CountDownLatch присваивается начальное значение счетчика, а все задачи, вызвавшие await() для этого объекта, блокируются до момента обнуления счетчика. Другие задачи могут уменьшать счетчик, вызывая метод countDown() для объекта (обычно это делается тогда, когда задача завершает свою работу). Класс CountDownLatch рассчитан на «одноразовое» применение; счетчик не может возвращаться к прежнему состоянию. Если вам нужна версия с возможностью сброса счетчика, воспользуйтесь классом CyclicBarrier.
Задачи, вызывающие countDown(), не блокируются на время вызова. Только вызов await() блокируется до момента обнуления счетчика.
Типичный способ применения — разделение задачи на п независимых подзадач и создание объекта CountDownLatch с начальным значением п. При завершении каждая подзадача вызывает countDown() для объекта синхронизации. Потоки, ожидающие решения общей задачи, блокируются вызовом await(). Описанная методика продемонстрирована в следующем примере:
// concurrency/CountDownLatchDemo java import java.util concurrent.*; import java util *.
import static net mindview util.Print *,
// ЧАсть основной задачи.
class TaskPortion implements Runnable {
private static int counter = 0.
private final int id = counter++;
private static Random rand = new Random(47);
private final CountDownLatch latch;
TaskPortion(CountDownLatch latch) { this latch = latch,
}
public void run() { try {
doWorkO;
latch countDownO; } catchdnterruptedException ex) {
// Приемлемый вариант выхода
}
}
public void doWorkO throws InterruptedException {
TimeUnit MILLISECONDS.sleep(rand nextlnt(2000)); pri nt(thi s + "завершается");
}
public String toStringO {
return String.format("^l$-3d ". id),
// Ожидание по объекту CountDownLatch: class WaitingTask implements Runnable { private static int counter = 0; private final int id = counter++; private final CountDownLatch latch, WaitingTask(CountDownLatch latch) { this latch = latch;
public void run() { try {
latch awaitO.
printC'Bapbep пройден для " + this); } catchdnterruptedException ex) {
print(this + " interrupted"),
}
}
public String toStringO {
return String format("WaitingTask %l%-36 id).
public class CountDownLatchDemo { static final int SIZE = 100.
public static void main(String[] args) throws Exception {
ExecutorService exec = Executors.newCachedThreadPoolО, // Все подзадачи совместно используют один объект CountDownLatch CountDownLatch latch = new CountDownLatch(SIZE); for(int i = 0; i < 10; i++)
exec.execute(new WaitingTask(1atch)); for(int i = 0; i < SIZE. i++)
exec execute(new TaskPortion(latch)). print("Запущены все задачи"); exec.shutdownO, // Выход по завершению всех задач