一、什么是信号量

“信号量”在编程术语中使用单词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

觉得对您有帮助的话,帮我点赞、分享!您的支持是我不竭的创作动力!。另外,笔者最近一段时间输出了如下的精品内容,期待您的关注。

[java并发编程]基于信号量semaphore实现限流器的更多相关文章

  1. Java并发编程笔记之Semaphore信号量源码分析

    JUC 中 Semaphore 的使用与原理分析,Semaphore 也是 Java 中的一个同步器,与 CountDownLatch 和 CycleBarrier 不同在于它内部的计数器是递增的,那 ...

  2. Java并发编程--5.信号量和障碍器

    Semaphore信号量 简介 它本质上是一个共享锁,限制访问公共资源的线程数目,它也被称为计数信号量acquire()许可一个线程, Semaphore – 1; 没有可用的许可时,Semaphor ...

  3. Java并发编程系列之Semaphore详解

    简单介绍 我们以饭店为例,假设饭店只有三个座位,一开始三个座位都是空的.这时如果同时来了三个客人,服务员人允许他们进去用餐,然后对外说暂无座位.后来的客人必须在门口等待,直到有客人离开.这时,如果有一 ...

  4. 【Java并发编程实战】-----“J.U.C”:Semaphore

    信号量Semaphore是一个控制访问多个共享资源的计数器,它本质上是一个"共享锁". Java并发提供了两种加锁模式:共享锁和独占锁.前面LZ介绍的ReentrantLock就是 ...

  5. Java并发编程的4个同步辅助类(CountDownLatch、CyclicBarrier、Semaphore、Phaser)

    我在<JDK1.5引入的concurrent包>中,曾经介绍过CountDownLatch.CyclicBarrier两个类,还给出了CountDownLatch的演示案例.这里再系统总结 ...

  6. Java并发编程:CountDownLatch、CyclicBarrier和Semaphore

    Java并发编程:CountDownLatch.CyclicBarrier和Semaphore 在java 1.5中,提供了一些非常有用的辅助类来帮助我们进行并发编程,比如CountDownLatch ...

  7. Java并发编程Semaphore

    信号量 信号量类Semaphore,用来保护对唯一共享资源的访问.一个简单的打印队列,并发任务进行打印,加入信号量同时之能有一个线程进行打印任务 . import java.util.concurre ...

  8. 【Java并发编程五】信号量

    一.概述 技术信号量用来控制能够同时访问某特定资源的活动的数量,或者同时执行某一给定操作的数据.计数信号量可以用来实现资源池或者给一个容器限定边界. 信号量维护了一个许可集,许可的初始量通过构造函数传 ...

  9. 14、Java并发编程:CountDownLatch、CyclicBarrier和Semaphore

    Java并发编程:CountDownLatch.CyclicBarrier和Semaphore 在java 1.5中,提供了一些非常有用的辅助类来帮助我们进行并发编程,比如CountDownLatch ...

随机推荐

  1. vue H5 超简单的swiper制作抖音上拉切换视频播放

    -----html部分------ <swiper vertical :style="{height: windowheight+'px',width:375+'px'}" ...

  2. 第一天·浏览器内核及Web标准

    一·浏览器及浏览器内核 1.常见的浏览器 (1)IE浏览器 IE是微软公司旗下浏览器,是目国内用户量最多的浏览器.IE诞生于1994年,当时微软为了对抗市场份额占据将近百分之九十的网景Netscape ...

  3. 分享一个react 图片上传组件 支持OSS 七牛云

    react-uplod-img 是一个基于 React antd组件的图片上传组件 支持oss qiniu等服务端自定义获取签名,批量上传, 预览, 删除, 排序等功能 需要 react 版本大于 v ...

  4. vue+koa2即时聊天,实时推送比特币价格,爬取电影网站

    技术栈 vue+vuex+vue-router+socket.io+koa2+mongodb+pm2自动化部署+图灵机器人+[npm script打包,cdn同步,服务器上传一个命令全搞定] 功能清单 ...

  5. ES6-11学习笔记--const

    新声明方式:const 1.不属于顶层对象 window 2.不允许重复声明 3.不存在变量提升 4.暂时性死区 5.块级作用域   以上特性跟let声明一样,特性可看 let 的学习笔记:链接跳转 ...

  6. Python窗口学习之监听窗口变化触发函数

    在窗口大小发生变化后,往往组件也需要调整 代码: #空间适应屏幕 def window_resiz(self,event=None): print(window.winfo_height()) pri ...

  7. 【每日日报】第四十七天---<div>

    1 学习HTML HTML <div> 元素是块级元素,它可用于组合其他 HTML 元素的容器. <div> 元素没有特定的含义.除此之外,由于它属于块级元素,浏览器会在其前后 ...

  8. Androd点击一个选框取消其他选框

    说明: 我做的体温填报系统需要在填报体温时勾选有无特殊情况 当勾选'无'时需要将用户勾选的其他选框取消 当勾选其他选框时需要将'无'这个选框取消 效果: 代码: addTem.xml <Line ...

  9. IDEA小技巧:Debug条件断点

    今天给大家分享一个IDEA调试过程中的一个小技巧. 先来说说场景,你有没有碰到类似的情况,一个循环结构里,中间某一个情况可能会出错.比如下面的代码结果中,可能执行到第27次的时候,会出现问题. for ...

  10. c语言实现双链表的基本操作—增删改查

    //初始化 Node*InitList() { Node*head=(Node*)malloc(sizeof(Node)); if(NULL==head) { printf("内存分配失败! ...