Semaphore в Java
Last updated: 6 мая 2025 г.Обычно нужен если много потоков одновременно пытаются получить доступ к каким-то ресурсам, а нам нужно, чтобы к ним одновременно получала доступ только часть из потоков, при этом, оставшиеся потоки стояли в очереди и если какой-то поток оставил ресурс, нужно, чтобы сразу занимал его место один из стоящих в очереди.
Пример программы:
1import java.io.*;
2import java.util.concurrent.Semaphore;
3
4public class SemaphoreExample {
5 public static void main(String[] args) {
6 Semaphore resources = new Semaphore(3); // три разрешения
7 // То есть одновременно могут выполняться только
8 // три потока, все остальные стоят в очереди пока
9 // одно из трех мест не освободится.
10 for (int i = 1; i < 10; i++) {
11 SomeThread t = new SomeThread();
12 t.setName("Thread " + i);
13 t.resources = resources;
14 t.start();
15 }
16 }
17}
18
19class SomeThread extends Thread {
20 Semaphore resources;
21
22 @Override
23 public void run() {
24 try {
25 // Поток занимает одно из трех разрешений
26 resources.acquire();
27 System.out.println(
28 Thread.currentThread().getName()
29 + " entered the resource"
30 );
31 Thread.sleep(1000);
32 System.out.println(
33 Thread.currentThread().getName()
34 + " left the resource"
35 );
36 resources.release(); // Поток покидает одно
37 // из трех разрешений, после этого оставленное
38 // разрешение сразу занимает другой поток,
39 // стоявший в очереди на занятие разрешения,
40 // поскольку не мог занять разрешение, так как
41 // все три были заняты другими потоками.
42 } catch (InterruptedException e) {}
43 }
44}
Вывод:

Из консоли видно, что одновременно выполняются только три потока.
Программа выполняется в следующей последовательности:
Видим, что сначала выполняются только 1,2,3 поток.
Потом 1,2 поток завершают свое выполнение. И на их место стразу становятся 4,6 потоки, которые стояли в очереди.
Далее завершает свою работу 3 поток, и на его место сразу становиться 5 поток.
То есть, очевидно, что параллельно друг другу всё время работают только три потока.
Следующие уроки
ReentrantLock - гибкая альтернатива synchronized
11
мин.
Ожидание завершения потоков с помощью CountDownLatch
10
мин.
CyclicBarrier в Java
10
мин.