当前位置:网站首页>并发编程学习笔记 之 工具类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个许可证可被使用。
边栏推荐
- 以‘智’提‘质|金融影像平台解决方案
- Okaleido tiger logged into binance NFT on July 27, and has achieved good results in the first round
- 完全去中心化的编程模式,不需要服务器,也不需要ip,就像一张漫无目的的网络、四处延伸
- Super simple integration of HMS ml kit to realize parent control
- Print out all prime numbers between 1-100
- Laravel服务容器(上下文绑定的运用)
- Detailed steps of JDBC connection to database
- “山东大学移动互联网开发技术教学网站建设”项目实训日志一
- Okaleido Tiger 7.27日登录Binance NFT,首轮已获不俗成绩
- MySql统计函数COUNT详解
猜你喜欢
识变!应变!求变!
datax安装
中海油集团,桌面云&网盘存储系统应用案例
The Platonic metauniverse advocated by musk has long been verified by platofarm
“山东大学移动互联网开发技术教学网站建设”项目实训日志七
深度学习的趣味app简单优化(适合新手)
File文件上传的使用(2)--上传到阿里云Oss文件服务器
Laravel swagger add access password
Extreme deflation and perpetual motion machine model will promote the outbreak of platofarm
闪贷Dapp的调研及实现
随机推荐
30 knowledge points that must be mastered in quantitative development [what is level-2 data]
『全闪实测』数据库加速解决方案
day02作业之进程管理
DAO赛道异军突起,M-DAO的优势在哪里?
与张小姐的春夏秋冬(1)
DeFi 2.0的LaaS协议,重振DeFi赛道发展的关键
Breaking through the hardware bottleneck (I): the development of Intel Architecture and bottleneck mining
SSM integration
Laravel service container (inheritance and events)
重庆大道云行作为软件产业代表受邀参加渝中区重点项目签约仪式
Machine learning makes character recognition easier: kotlin+mvvm+ Huawei ml Kit
焕然一新,swagger UI 主题更改
Sports health is deeply rooted in the hearts of the people, and move protocol leads quality life
Countdown of the uniapp component (such as the countdown to reading the agreement and the countdown to completing learning)
改哭了,终于解决了Cannot read properties of undefined (reading ‘parseComponent‘)
Windows下cmd窗口连接mysql并操作表
“山东大学移动互联网开发技术教学网站建设”项目实训日志七
数组的基础使用--遍历循环数组求出数组最大值,最小值以及最大值下标,最小值下标
如何零代码制作深度学习的趣味app(适合新手)
Most PHP programmers don't understand how to deploy safe code