[TOC]
一、什么是信号量
“信号量”在编程术语中应用单词 semaphore,那什么是“信号量”?信号量就好比你家厨房入口架子上摆了三把锅。
- 如果你的孩子热奶拿走一把,你的老婆热汤拿走一把,你的妈妈做菜拿走一把,你想煮面条就没有锅了。当你看到这种状况,你就不会进入厨房了,你处于期待状态。也就说厨房依照“锅的数量”作为信号量,只能包容三个人(线程)。
- 当你的老婆热完汤之后,把锅从新放回架子上,你就能够去取得一个锅,你就能够进入厨房了。
二、信号量类 Semaphore
通过上文的介绍,咱们能够总结出信号量的重要组成部分
- 计数器:计算信号量的应用状况,锅 (信号) 被应用一次减 1,锅 (信号) 被还回一次加 1
- 期待队列:当工作数量大于信号量数量下限的时候,工作进入期待队列
信号量在 JDK 中是由 java.util.concurrent.Semaphore 实现的,Semaphore 提供了两个构造函数。permits 参数代表信号量的数量 (锅的数量),fair 代表信号量的获取是否遵循偏心准则。所谓的偏心准则就是:先启动的线程先调用semaphore.acquire();
办法,就先失去一个信号“锅”(permit),遵循先来后到的准则。
public Semaphore(int permits)
public Semaphore(int permits, boolean fair)
罕用办法列表
办法名 | 作用 |
---|---|
acquire() | 获取一个 permit,在获取到 permit 之前,线程处于阻塞状态 |
tryAcquire() | 尝试获取一个 permit,获取胜利返回 true,否则返回 false,不阻塞线程 |
tryAcquire(long timeout, TimeUnit unit) | 和 tryAcquire()大部分实现一样,区别是提供超时设置,在超时工夫范畴内屡次尝试,不阻塞线程。 |
availablePermits() | 获取目前残余的信号 permit 的数量 |
release() | 开释一个 permit,并唤醒一个期待信号 permit 的线程 |
hasQueuedThreads() | 返回值 boolean 类型,判断期待队列中是否存在期待线程 |
getQueueLength() | 获取期待队列中期待线程的数量 |
三、实现限流器
通过下面的介绍,我置信大家必定能够想到 Semaphore 的利用场景。比方:
- 医院门诊排号器,三个在岗医生就是 3 个信号 permit,当超出信号量数量的时候,想就诊就只能期待
- 停车场停车性能,n 个车位就是 n 个信号 permit,当超出信号量数量的时候,想停车也只能期待
利用场景还有很多很多,大家本人去发会创造力吧。其实无论多少种利用场景说白了:Semaphore 实现的就是一个限流器。咱们还是以咱们家的厨房 kitchen 外面的三把锅 wok 为例,实现基于信号量的限流。
public class TestKitchenSemaphore {
// 信号量 - 3 把锅
private static Semaphore threeWoks = new Semaphore(3);
public static void main(String[] args) throws InterruptedException {
// 模仿 5 集体抢占 3 把锅的场景
for(int i=0;i < 5;i++){Thread.sleep(1000); // 模仿进入厨房的先后顺序,存在工夫距离
new Thread(() -> {
try {threeWoks.acquire(); // 获取一个 permit,信号量计数器减 1
System.out.println(Thread.currentThread().getName()
+ "拿走了一把锅,还剩" + threeWoks.availablePermits() + "把锅");
Thread.sleep(new Random().nextInt(5000)); // 模仿应用锅的时长
threeWoks.release();// 开释 permit,信号量计数器加 1
System.out.println(Thread.currentThread().getName()
+ "还回一把锅,还剩" + threeWoks.availablePermits() + "把锅");
} catch (InterruptedException e) {e.printStackTrace();
}
}).start();}
}
}
上文代码的输入如下,咱们能够看到每 acquire 一次信号量减 1,每 release 一次信号量加 1。信号量的下限是 3,上限是 0。当达到下限的时候,只有等先占据锅 permit 的线程开释,其余线程能力获取到锅 permit。
Thread- 0 拿走了一把锅,还剩 2 把锅
Thread- 1 拿走了一把锅,还剩 1 把锅
Thread- 2 拿走了一把锅,还剩 0 把锅 => 备注:5 个线程只能获取 3 个锅(下限)Thread- 1 还回一把锅,还剩 1 把锅
Thread- 3 拿走了一把锅,还剩 0 把锅 => 备注:被还回能力被再次占用,不超过 3
Thread- 0 还回一把锅,还剩 1 把锅
Thread- 4 拿走了一把锅,还剩 0 把锅 => 备注:被还回能力被再次占用,不超过 3
Thread- 2 还回一把锅,还剩 1 把锅
Thread- 3 还回一把锅,还剩 2 把锅
Thread- 4 还回一把锅,还剩 3 把锅 => 备注:用完顺次开释
欢送关注我的博客,更多精品常识合集
本文转载注明出处(必须带连贯,不能只转文字):字母哥博客 – zimug.com
感觉对您有帮忙的话,帮我点赞、分享!您的反对是我不竭的创作能源!。另外,笔者最近一段时间输入了如下的精品内容,期待您的关注。
- 《kafka 修炼之道》
- 《手摸手教你学 Spring Boot2.0》
- 《Spring Security-JWT-OAuth2 一本通》
- 《实战前后端拆散 RBAC 权限管理系统》
- 《实战 SpringCloud 微服务从青铜到王者》