当前位置:网站首页>并发编程学习笔记 之 工具类Semaphore(信号量)
并发编程学习笔记 之 工具类Semaphore(信号量)
2022-07-29 05:20:00 【姠惢荇者】
1、概念
Semaphore(信号量)是一个线程同步工具,主要用于在一个时刻允许多个线程对共享资源进行并行操作的场景。通常情况下,使用Semaphore的过程实际上是多个线程获取访问共享资源许可证的过程。
Semaphore内部逻辑:
- 如果此时Semaphore内部的计数器大于零,那么线程将可以获得小于该计数器数量的许可证,同时还会导致Semaphore内部的计数器减少所发放的许可证数量。
- 如果此时Semaphore内部的计数器等于0,也就是说没有可用的许可证,那么当前线程有可能会被阻塞(使用tryAcquire方法时不会阻塞)。
- 当线程不再使用许可证时,需要立即将其释放以供其他线程使用,所以建议将许可证的获取以及释放动作写在try…finally语句块中。
2、Semaphore使用示例
这里模拟最大人数的场景,当人数达到上限收,后续的线程就无法进入,当有信号量被释放后,后续的线程可以继续进入。
public class SemaphoreTest {
public static void main(String[] args) {
final LoginService loginService = new LoginService(5);
for (int i=0;i<10;i++){
Thread thread = new Thread(()->{
if(loginService.login()){
try {
//模拟游玩时间
TimeUnit.SECONDS.sleep(new Random().nextInt(5));
System.out.println(Thread.currentThread().getName() + ",开始游玩!");
} catch (InterruptedException e) {
e.printStackTrace();
}finally {
loginService.logout();
}
}else{
System.out.println(Thread.currentThread().getName() + "人满,回家睡觉!");
}
});
thread.start();
}
}
private static class LoginService{
private final Semaphore semaphore;
public LoginService(int maxUser){
this.semaphore = new Semaphore(maxUser,true);
}
public boolean login(){
if(semaphore.tryAcquire()){
System.out.println(Thread.currentThread().getName() + ",进园成功!");
return true;
}
return false;
}
public void logout(){
semaphore.release();
System.out.println(Thread.currentThread().getName() + ",出园!");
}
}
}
Thread-0,进园成功!
Thread-1,进园成功!
Thread-2,进园成功!
Thread-3,进园成功!
Thread-4,进园成功!
Thread-5人满,回家睡觉!
Thread-6人满,回家睡觉!
Thread-3,开始游玩!
Thread-3,出园!
Thread-7,进园成功!
Thread-9人满,回家睡觉!
Thread-8人满,回家睡觉!
Thread-0,开始游玩!
Thread-0,出园!
Thread-1,开始游玩!
Thread-1,出园!
Thread-7,开始游玩!
Thread-7,出园!
Thread-4,开始游玩!
Thread-4,出园!
Thread-2,开始游玩!
Thread-2,出园!
在上述示例中,线程“Thread-7”等到有是否资源后,又可以获取进入资格了。
release方法: 在Semaphore设计中,并未强制要求执行release操作的线程必须是执行了acquire的线程才可以,而是需要开发人员自身具有相应的编程约束来确保Semaphore的正确使用,这样就可能造成不是获取到信号量的线程调用了release方法,从而造成信号量的错误释放。错误示例如下,本来主线程不应该获取到信号量,但是实际上因为t2线程的中断,执行了finally 的中的release方法,造成了信号量的错误释放。
public class Semaphore2Test {
public static void main(String[] args) throws InterruptedException {
//定义信号量
final Semaphore semaphore = new Semaphore(1,true);
Thread t1 = new Thread(()->{
try{
semaphore.acquire();
System.out.println("t1 获取到资源!");
TimeUnit.HOURS.sleep(1);
}catch (Exception e){
System.out.println("t1 当前线程被中断!");
}finally {
semaphore.release();
}
});
Thread t2 = new Thread(()->{
try{
semaphore.acquire();
System.out.println("t2 获取到资源!");
}catch (Exception e){
System.out.println("t2 当前线程被中断!");
}finally {
semaphore.release();
}
});
t1.start();
TimeUnit.SECONDS.sleep(2);
t2.start();
TimeUnit.SECONDS.sleep(2);
t2.interrupt();
semaphore.acquire();
System.out.println("主线程获取资源访问权限!");
}
}
3、Semaphore常用方法
1、构造函数
有两个构造函数。其中,所谓的公平信号量是获得锁的顺序与线程启动顺序有关,但不代表100%地获得信号量,仅仅是在概率上能得到保证。而非公平信号量就是无关的。
- public Semaphore(int permits):定义Semaphore指定许可证数量,并且指定非公平的同步器,因此new Semaphore(n)实际上是等价于new Semaphore(n,false)的。
- public Semaphore(int permits, boolean fair):定义Semaphore指定许可证数量的同时给定非公平或是公平同步器。
2、tryAcquire方法
tryAcquire方法尝试向Semaphore获取许可证,如果此时许可证的数量少于申请的数量,则对应的线程会立即返回,结果为false表示申请失败,tryAcquire包含如下:
- tryAcquire():尝试获取Semaphore的许可证,该方法只会向Semaphore申请一个许可证,在Semaphore内部的可用许可证数量大于等于1的情况下,许可证将会获取成功,反之获取许可证则会失败,并且返回结果为false。
- boolean tryAcquire(long timeout, TimeUnit unit) throws InterruptedException:该方法与tryAcquire无参方法类似,同样也是尝试获取一个许可证,但是增加了超时参数。如果在超时时间内还是没有可用的许可证,那么线程就会进入阻塞状态,直到到达超时时间或者在超时时间内有可用的证书(被其他线程释放的证书),或者阻塞中的线程被其他线程执行了中断。
- boolean tryAcquire(int permits):在使用无参的tryAcquire时只会向Semaphore尝试获取一个许可证,但是该方法会向Semaphore尝试获取指定数目的许可证。
- boolean tryAcquire(int permits, long timeout, TimeUnit unit):该方法与第二个方法类似,只不过其可以指定尝试获取许可证数量的参数
3、acquire方法
acquire方法也是向Semaphore获取许可证,但是该方法比较偏执一些,获取不到就会一直等(陷入阻塞状态),但是可以被其他线程中断,Semaphore为我们提供了acquire方法的两种重载形式:
- void acquire():该方法会向Semaphore获取一个许可证,如果获取不到就会一直等待,直到Semaphore有可用的许可证为止,或者被其他线程中断。当然,如果有可用的许可证则会立即返回。
- void acquire(int permits):该方法会向Semaphore获取指定数量的许可证,如果获取不到就会一直等待,直到Semaphore有可用的相应数量的许可证为止,或者被其他线程中断。同样,如果有可用的permits个许可证则会立即返回。
4、acquireUninterruptibly方法
和acquire方法相比,不会被其他线程中断。
- void acquireUninterruptibly():该方法会向Semaphore获取一个许可证,如果获取不到就会一直等待,与此同时对该线程的任何中断操作都会被无视,直到Semaphore有可用的许可证为止。当然,如果有可用的许可证则会立即返回。
- void acquireUninterruptibly(int permits):该方法会向Semaphore获取指定数量的许可证,如果获取不到就会一直等待,与此同时对该线程的任何中断操作都会被无视,直到Semaphore有可用的许可证为止,或者被其他线程中断。同样,如果有可用的permits个许可证则会立即返回。
5、release方法
release方法需要正确使用,避免出现上述提到的情况。
- void release():释放一个许可证,并且在Semaphore的内部,可用许可证的计数器会随之加一,表明当前有一个新的许可证可被使用。
- void release(int permits):释放指定数量(permits)的许可证,并且在Semaphore内部,可用许可证的计数器会随之增加permits个,表明当前又有permits个许可证可被使用。
边栏推荐
- Strategic cooperation with many institutions shows the strength of the leading company of platofarm yuancosmos
- 浅谈分布式全闪存储自动化测试平台设计
- 运动健康深入人心,MOVE PROTOCOL引领品质生活
- Detailed steps of JDBC connection to database
- Super simple integration HMS ml kit face detection to achieve cute stickers
- 量化开发必掌握的30个知识点【什么是Level-2数据】
- 从Starfish OS持续对SFO的通缩消耗,长远看SFO的价值
- 闪贷Dapp的调研及实现
- 新手入门:手把手从PHP环境到ThinkPHP6框架下载
- PHP write a diaper to buy the lowest price in the whole network
猜你喜欢

量化开发必掌握的30个知识点【什么是Level-2数据】

Sliding switch of tab of uniapp component

Starfish OS:以现实为纽带,打造元宇宙新范式

性能对比|FASS iSCSI vs NVMe/TCP

Fantom (FTM) prices will soar by 20% in the next few days

我的理想工作,码农的绝对自由支配才是最重要的——未来创业的追求

与张小姐的春夏秋冬(3)

Crypto巨头们ALL IN元宇宙,PlatoFarm或能突围

Thinkphp6 pipeline mode pipeline use

“山东大学移动互联网开发技术教学网站建设”项目实训日志四
随机推荐
如何零代码制作深度学习的趣味app(适合新手)
华为2020校招笔试编程题 看这篇就够了(下)
Huawei 2020 school recruitment written test programming questions read this article is enough (Part 2)
一文读懂Move2Earn项目——MOVE
突破硬件瓶颈(一):Intel体系架构的发展与瓶颈挖掘
Move protocol global health declaration, carry out the health campaign to the end
The bear market is slow, and bit.store provides stable stacking products to help you get through the bull and bear market
量化开发必掌握的30个知识点【什么是Level-2数据】
Windows下cmd窗口连接mysql并操作表
PHP write a diaper to buy the lowest price in the whole network
Training log 6 of the project "construction of Shandong University mobile Internet development technology teaching website"
win10+opencv3.2+vs2015配置
Laravel service container (Application of context binding)
从Starfish OS持续对SFO的通缩消耗,长远看SFO的价值
ssm整合
Print out all prime numbers between 1-100
File permissions of day02 operation
Novice introduction: download from PHP environment to thinkphp6 framework by hand
Shanzhai coin Shib has a US $548.6 million stake in eth whale's portfolio - traders should be on guard
Differences between href and SRC