CountDownLatch и Semaphore
В общем то,достаточно сжатая информация об удобных вещах в пакете java.util.concurrent,
а точнее о паре вещей оттуда.
CountDownLatch
CountDownLatch класс защелка,позволяет задержать поток(и) до тех пор,пока не выполнится определенное условие,а именно пока счетчик заданный в конструкторе не дойдет до 0.
Вообще создание объекта происходит следующим образом
CountDownLatch latch = new CountDownLatch(3);//по количеству потоков которых мы будем ждать
И 2 основных метода
countDown и await.
Метод await заставляет текущий поток ожидать,пока счетчик защелки не станет равен 0.
Метод countDown декрементит счетчик заданный в конструкторе и как только он дойдет до 0,потоки продолжат выполнение.
Вот пример со скачками(пример не мой,я только напихал больше комментариев по коду,ну и сократил лишнее)
class Race
{
private Random rand = new Random();
private int distance = 50;
private List horses = Arrays.asList("Vanek","Robert","Polson","Rak");
public void run() throws InterruptedException
{
System.out.println("And the horses are stepping up to the gate...");
final CountDownLatch start = new CountDownLatch(1);//защелка для одновременного старта для всех коней,1-тк защелка для основного потока выполнения
start.await();
final CountDownLatch finish = new CountDownLatch(horses.size());//защелка для финиша, а здесь по количеству лошадей
final List places = Collections.synchronizedList(new ArrayList<>());
horses.forEach(horse -> new Thread(() -> {
try {
System.out.println(horse + " stepping up to the gate...");
start.await(); // Блокируем поток,чтобы не было не одного фальстарта у наших коней
int traveled = 0;//пройденный путь для коня
while (traveled < distance) {
// каждые 0-2 секунды лошадь проходит дистанцию 0-14 пунктов
Thread.sleep(rand.nextInt(3) * 1000);
traveled += rand.nextInt(15);
System.out.println(horse + " advanced to " + traveled + "!");
}
finish.countDown();//уменьшение счетчика защелки,тк мы будем ждать именно этого момента в самой программе и когда последний конь финиширует исполнение завершится
System.out.println(horse + " crossed the finish!");
places.add(horse);
} catch (InterruptedException intEx) {
System.out.println("ABORTING RACE!!!");
intEx.printStackTrace();
}
}).start());
System.out.println("And... they're off!");
start.countDown();//снимаем нашу защелку для старта
finish.await();//ожидаем финиша наших скакунов
System.out.println("And we have our winners!");
System.out.println(places.get(0) + " took the gold...");
System.out.println(places.get(1) + " got the silver...");
System.out.println("and " + places.get(2) + " took home the bronze.");
}
public static void main(String[] args) throws InterruptedException {
new Race().run();
}
}
Вот как то так.
Теперь про класс Semaphore.
Он, как видно из названия,служит для ограничения количества потоков использующих определенный ресурс.
Создается объект как то так
Semaphore available = new Semaphore(3);//по количеству потоков которые будут активны
И 2 основных метода acquire() и release().
acquire()-Уменьшает счетчик доступных потоков(который мы задали в конструкторе) на 1.
release()-Соответственно освобождает его и увеличивает счетчик.
Небольшой пример
public static void main(String[] args)
{
Runnable limitedCall = new Runnable() {
final Random rand = new Random();
final Semaphore available = new Semaphore(3);
int count = 0;
public void run()
{
int time = rand.nextInt(15);
int num = count++;
try
{
available.acquire();//задействуем поток
System.out.println("Executing " +
"long-running action for " +time +
" seconds... #" + num);
Thread.sleep(time * 1000);
System.out.println("Done with #" + num + "!");
available.release();//после его работы освобождаем
}
catch (InterruptedException intEx)
{
intEx.printStackTrace();
}
}
};
for (int i=0; i<10 data-blogger-escaped-i="" data-blogger-escaped-limitedcall="" data-blogger-escaped-new="" data-blogger-escaped-pre="" data-blogger-escaped-start="" data-blogger-escaped-thread="">
Создаем 10 потоков(можно убедиться выполнив команду jstack),однако только 3 из них активны.Как только один их потоков освобождает семафор,другой занимает его место.
Вот и все.