一、Semaphore
-
Semaphore 是 Java 并发包(
java.util.concurrent
)中提供的一个同步工具类 -
Semaphore 用于控制对共享资源的并发访问,它基于经典的信号量概念
-
Semaphore 维护了一组许可证(permits),线程可以获取许可证,也可以释放许可证
-
如果没有可用的许可证,将阻塞线程,直到有许可证可用或线程被中断
二、构造方法
1、基本介绍
Semaphore(int permits)
- 创建具有给定许可数量的信号量,非公平模式
Semaphore(int permits, boolean fair)
- 创建具有给定许可数量的信号量,并指定公平模式
2、演示
Semaphore unfairSemaphore = new Semaphore(3);
Semaphore fairSemaphore = new Semaphore(3, true);
三、核心方法
1、获取许可
void acquire() throws InterruptedException
- 获取一个许可,阻塞直到获取成功或线程被中断
void acquire(int permits) throws InterruptedException
- 获取指定数量的许可,阻塞直到获取成功或线程被中断
boolean tryAcquire()
- 尝试获取一个许可,立即返回获取结果
boolean tryAcquire(int permits)
- 尝试获取指定数量的许可,立即返回获取结果
boolean tryAcquire(long timeout, TimeUnit unit) throws InterruptedException
- 尝试获取一个许可,等待指定时间后返回获取结果
boolean tryAcquire(int permits, long timeout, TimeUnit unit) throws InterruptedException
- 尝试获取指定数量的许可,等待指定时间后返回获取结果
2、释放许可
void release()
- 释放一个许可
void release(int permits)
- 释放指定数量的许可
3、演示
tryAcquire()
+release()
Semaphore semaphore = new Semaphore(2);
ExecutorService executor = Executors.newFixedThreadPool(4);
for (int i = 1; i <= 4; i++) {
int id = i;
executor.execute(() -> {
try {
System.out.println("线程 " + id + " 尝试获取许可...");
semaphore.acquire();
System.out.println("线程 " + id + " 获取许可成功,剩余许可: " + semaphore.availablePermits());
// 模拟工作
Thread.sleep(2000);
System.out.println("线程 " + id + " 释放许可");
semaphore.release();
} catch (InterruptedException e) {
e.printStackTrace();
}
});
}
executor.shutdown();
# 输出结果
线程 3 尝试获取许可...
线程 1 尝试获取许可...
线程 2 尝试获取许可...
线程 4 尝试获取许可...
线程 1 获取许可成功,剩余许可: 0
线程 3 获取许可成功,剩余许可: 1
线程 1 释放许可
线程 3 释放许可
线程 2 获取许可成功,剩余许可: 1
线程 4 获取许可成功,剩余许可: 0
线程 2 释放许可
线程 4 释放许可
acquire(int permits)
+release(int permits)
Semaphore semaphore = new Semaphore(2);
ExecutorService executor = Executors.newFixedThreadPool(4);
for (int i = 1; i <= 4; i++) {
int id = i;
executor.execute(() -> {
try {
System.out.println("线程 " + id + " 尝试获取许可...");
semaphore.acquire(2);
System.out.println("线程 " + id + " 获取许可成功,剩余许可: " + semaphore.availablePermits());
// 模拟工作
Thread.sleep(2000);
System.out.println("线程 " + id + " 释放许可");
semaphore.release(2);
} catch (InterruptedException e) {
e.printStackTrace();
}
});
}
executor.shutdown();
# 输出结果
线程 1 尝试获取许可...
线程 4 尝试获取许可...
线程 3 尝试获取许可...
线程 2 尝试获取许可...
线程 1 获取许可成功,剩余许可: 0
线程 1 释放许可
线程 2 获取许可成功,剩余许可: 0
线程 2 释放许可
线程 3 获取许可成功,剩余许可: 0
线程 3 释放许可
线程 4 获取许可成功,剩余许可: 0
线程 4 释放许可
tryAcquire()
+release()
Semaphore semaphore = new Semaphore(2);
ExecutorService executor = Executors.newFixedThreadPool(4);
for (int i = 1; i <= 4; i++) {
int id = i;
executor.execute(() -> {
try {
System.out.println("线程 " + id + " 尝试获取许可...");
boolean b = semaphore.tryAcquire();
if (!b) {
System.out.println("线程 " + id + " 获取许可失败");
return;
}
System.out.println("线程 " + id + " 获取许可成功,剩余许可: " + semaphore.availablePermits());
// 模拟工作
Thread.sleep(2000);
System.out.println("线程 " + id + " 释放许可");
semaphore.release();
} catch (InterruptedException e) {
e.printStackTrace();
}
});
}
executor.shutdown();
# 输出结果
线程 4 尝试获取许可...
线程 2 尝试获取许可...
线程 1 尝试获取许可...
线程 3 尝试获取许可...
线程 1 获取许可失败
线程 3 获取许可失败
线程 2 获取许可成功,剩余许可: 0
线程 4 获取许可成功,剩余许可: 1
线程 4 释放许可
线程 2 释放许可
tryAcquire(long timeout, TimeUnit unit)
+release()
Semaphore semaphore = new Semaphore(2);
ExecutorService executor = Executors.newFixedThreadPool(4);
for (int i = 1; i <= 4; i++) {
int id = i;
executor.execute(() -> {
try {
System.out.println("线程 " + id + " 尝试获取许可...");
boolean b = semaphore.tryAcquire(1, TimeUnit.SECONDS);
if (!b) {
System.out.println("线程 " + id + " 获取许可失败");
return;
}
System.out.println("线程 " + id + " 获取许可成功,剩余许可: " + semaphore.availablePermits());
// 模拟工作
Thread.sleep(2000);
System.out.println("线程 " + id + " 释放许可");
semaphore.release();
} catch (InterruptedException e) {
e.printStackTrace();
}
});
}
executor.shutdown();
# 输出结果
线程 4 尝试获取许可...
线程 2 尝试获取许可...
线程 3 尝试获取许可...
线程 1 尝试获取许可...
线程 2 获取许可成功,剩余许可: 0
线程 4 获取许可成功,剩余许可: 1
线程 1 获取许可失败
线程 3 获取许可失败
线程 4 释放许可
线程 2 释放许可
tryAcquire(int permits, long timeout, TimeUnit unit)
+release()
Semaphore semaphore = new Semaphore(2);
ExecutorService executor = Executors.newFixedThreadPool(4);
for (int i = 1; i <= 4; i++) {
int id = i;
executor.execute(() -> {
try {
System.out.println("线程 " + id + " 尝试获取许可...");
boolean b = semaphore.tryAcquire(2, 1, TimeUnit.SECONDS);
if (!b) {
System.out.println("线程 " + id + " 获取许可失败");
return;
}
System.out.println("线程 " + id + " 获取许可成功,剩余许可: " + semaphore.availablePermits());
// 模拟工作
Thread.sleep(2000);
System.out.println("线程 " + id + " 释放许可");
semaphore.release(2);
} catch (InterruptedException e) {
e.printStackTrace();
}
});
}
executor.shutdown();
# 输出结果
线程 2 尝试获取许可...
线程 3 尝试获取许可...
线程 4 尝试获取许可...
线程 1 尝试获取许可...
线程 2 获取许可成功,剩余许可: 0
线程 4 获取许可失败
线程 3 获取许可失败
线程 1 获取许可失败
线程 2 释放许可
四、其他方法
1、基本介绍
int availablePermits()
- 返回当前可用的许可数量
int drainPermits()
- 获取并返回所有立即可用的许可
boolean isFair()
- 判断是否是公平模式
boolean hasQueuedThreads()
- 查询是否有线程正在等待获取
int getQueueLength()
- 返回等待获取的线程数的估计值
2、演示
availablePermits()
Semaphore semaphore = new Semaphore(2);
System.out.println("初始可用许可: " + semaphore.availablePermits());
try {
semaphore.acquire();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("获取 1 个许可后,可用许可: " + semaphore.availablePermits());
# 输出结果
初始可用许可: 2
获取 1 个许可后,可用许可: 1
drainPermits()
Semaphore semaphore = new Semaphore(2);
System.out.println("初始可用许可: " + semaphore.availablePermits());
int i = semaphore.drainPermits();
System.out.println("获取 " + i + " 个许可后,可用许可: " + semaphore.availablePermits());
# 输出结果
初始可用许可: 2
获取 2 个许可后,可用许可: 0
isFair()
Semaphore unfairSemaphore = new Semaphore(3);
System.out.println(unfairSemaphore.isFair());
Semaphore fairSemaphore = new Semaphore(3, true);
System.out.println(fairSemaphore.isFair());
# 输出结果
false
true
hasQueuedThreads()
+getQueueLength()
Semaphore semaphore = new Semaphore(1);
try {
semaphore.acquire();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("主线程获取许可");
for (int i = 1; i <= 3; i++) {
int id = i;
new Thread(() -> {
try {
semaphore.acquire();
System.out.println("线程" + id + "获取许可");
semaphore.release();
System.out.println("线程" + id + "释放许可");
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
}).start();
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("是否有线程在等待: " + semaphore.hasQueuedThreads());
System.out.println("等待队列长度: " + semaphore.getQueueLength());
semaphore.release();
System.out.println("主线程释放许可");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("是否有线程在等待: " + semaphore.hasQueuedThreads());
System.out.println("等待队列长度: " + semaphore.getQueueLength());
# 输出结果
主线程获取许可
是否有线程在等待: true
等待队列长度: 3
主线程释放许可
线程1获取许可
线程2获取许可
线程3获取许可
线程3释放许可
线程1释放许可
线程2释放许可
是否有线程在等待: false
等待队列长度: 0