Semaphore в Java

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

Пример программы:

import java.io.*; import java.util.concurrent.Semaphore; public class SemaphoreExample { public static void main(String[] args) { Semaphore resources = new Semaphore(3); // три разрешения // То есть одновременно могут выполняться только // три потока, все остальные стоят в очереди пока // одно из трех мест не освободится. for (int i = 1; i < 10; i++) { SomeThread t = new SomeThread(); t.setName("Thread " + i); t.resources = resources; t.start(); } } } class SomeThread extends Thread { Semaphore resources; @Override public void run() { try { // Поток занимает одно из трех разрешений resources.acquire(); System.out.println( Thread.currentThread().getName() + " entered the resource" ); Thread.sleep(1000); System.out.println( Thread.currentThread().getName() + " left the resource" ); resources.release(); // Поток покидает одно // из трех разрешений, после этого оставленное // разрешение сразу занимает другой поток, // стоявший в очереди на занятие разрешения, // поскольку не мог занять разрешение, так как // все три были заняты другими потоками. } catch (InterruptedException e) {} } }

Вывод:

Из консоли видно, что одновременно выполняются только три потока.

Example

Программа выполняется в следующей последовательности:

Видим, что сначала выполняются только 1,2,3 поток.

Потом 1,2 поток завершают свое выполнение. И на их место стразу становятся 4,6 потоки, которые стояли в очереди.

Далее завершает свою работу 3 поток, и на его место сразу становиться 5 поток.

То есть, очевидно, что параллельно друг другу всё время работают только три потока.

ReentrantLock - гибкая альтернатива synchronized

ReentrantLock в Java: мощная альтернатива synchronized с гибкой блокировкой любых участков кода. Примеры, отличия и преимущества для многопоточности.
Time to read: 11

Ожидание завершения потоков с помощью CountDownLatch

CountDownLatch в Java: механизм ожидания завершения потоков. Как использовать await() и countDown() для синхронизации. Практический пример и разбор работы.
Time to read: 10

CyclicBarrier в Java

Изучите CyclicBarrier в Java: как синхронизировать потоки и запускать дополнительное действие после завершения заданного количества потоков. Пример кода и объяснение работы.
Time to read: 10