Semaphore及其用法

1、Semaphore 是什么

Semaphore 通常我们叫它信号量, 可以用来控制同时访问特定资源的线程数量,通过协调各个线程,以保证合理的使用资源。

比如:停车场入口立着的那个显示屏,每有一辆车进入停车场显示屏就会显示剩余车位减1,每有一辆车从停车场出去,显示屏上显示的剩余车辆就会加1,当显示屏上的剩余车位为0时,停车场入口的栏杆就不会再打开,车辆就无法进入停车场了,直到有一辆车从停车场出去为止。

比如:在学生时代都去餐厅打过饭,假如有3个窗口可以打饭,同一时刻也只能有3名同学打饭。第四个人来了之后就必须在外面等着,只要有打饭的同学好了,就可以去相应的窗口了 。

 

2、使用场景

通常用于那些资源有明确访问数量限制的场景,常用于限流 。

比如:数据库连接池,同时进行连接的线程有数量限制,连接不能超过一定的数量,当连接达到了限制数量后,后面的线程只能排队等前面的线程释放了数据库连接才能获得数据库连接。

比如:停车场场景,车位数量有限,同时只能容纳多少台车,车位满了之后只有等里面的车离开停车场外面的车才可以进入。

3、Semaphore常用方法说明

acquire()  
获取一个令牌,在获取到令牌、或者被其他线程调用中断之前线程一直处于阻塞状态。
​
acquire(int permits)  
获取一个令牌,在获取到令牌、或者被其他线程调用中断、或超时之前线程一直处于阻塞状态。acquireUninterruptibly() 
获取一个令牌,在获取到令牌之前线程一直处于阻塞状态(忽略中断)。tryAcquire()
尝试获得令牌,返回获取令牌成功或失败,不阻塞线程。
​
tryAcquire(long timeout, TimeUnit unit)
尝试获得令牌,在超时时间内循环尝试获取,直到尝试获取成功或超时返回,不阻塞线程。
​
release()
释放一个令牌,唤醒一个获取令牌不成功的阻塞线程。
​
hasQueuedThreads()
等待队列里是否还存在等待线程。
​
getQueueLength()
获取等待队列里阻塞的线程数。
​
drainPermits()
清空令牌把可用令牌数置为0,返回清空令牌的数量。
​
availablePermits()
返回可用的令牌数量。

4、用semaphore 实现停车场提示牌功能。

每个停车场入口都有一个提示牌,上面显示着停车场的剩余车位还有多少,当剩余车位为0时,不允许车辆进入停车场,直到停车场里面有车离开停车场,这时提示牌上会显示新的剩余车位数。

业务场景 :

1、停车场容纳总停车量10。

2、当一辆车进入停车场后,显示牌的剩余车位数响应的减1.

3、每有一辆车驶出停车场后,显示牌的剩余车位数响应的加1。

4、停车场剩余车位不足时,车辆只能在外面等待。

代码:

public class TestCar {
​//停车场同时容纳的车辆10private  static  Semaphore semaphore=new Semaphore(10);
​public static void main(String[] args) {
​//模拟100辆车进入停车场for(int i=0;i<100;i++){
​Thread thread=new Thread(new Runnable() {public void run() {try {System.out.println("===="+Thread.currentThread().getName()+"来到停车场");if(semaphore.availablePermits()==0){System.out.println("车位不足,请耐心等待");}semaphore.acquire();//获取令牌尝试进入停车场System.out.println(Thread.currentThread().getName()+"成功进入停车场");Thread.sleep(new Random().nextInt(10000));//模拟车辆在停车场停留的时间System.out.println(Thread.currentThread().getName()+"驶出停车场");semaphore.release();//释放令牌,腾出停车场车位} catch (InterruptedException e) {e.printStackTrace();}}},i+"号车");
​thread.start();
​}
​}
}
​

5、Semaphore实现原理

(1)、Semaphore初始化。

Semaphore semaphore=new Semaphore(2);

1、当调用new Semaphore(2) 方法时,默认会创建一个非公平的锁的同步阻塞队列。

2、把初始令牌数量赋值给同步队列的state状态,state的值就代表当前所剩余的令牌数量。

初始化完成后同步队列信息如下图:

(2)获取令牌

semaphore.acquire();

1、当前线程会尝试去同步队列获取一个令牌,获取令牌的过程也就是使用原子的操作去修改同步队列的state ,获取一个令牌则修改为state=state-1。

2、 当计算出来的state<0,则代表令牌数量不足,此时会创建一个Node节点加入阻塞队列,挂起当前线程。

3、当计算出来的state>=0,则代表获取令牌成功。

源码:

/***  获取1个令牌*/public void acquire() throws InterruptedException {sync.acquireSharedInterruptibly(1);}

/*** 共享模式下获取令牌,获取成功则返回,失败则加入阻塞队列,挂起线程* @param arg* @throws InterruptedException*/public final void acquireSharedInterruptibly(int arg)throws InterruptedException {if (Thread.interrupted())throw new InterruptedException();//尝试获取令牌,arg为获取令牌个数,当可用令牌数减当前令牌数结果小于0,则创建一个节点加入阻塞队列,挂起当前线程。if (tryAcquireShared(arg) < 0)doAcquireSharedInterruptibly(arg);}

/*** 1、创建节点,加入阻塞队列,* 2、重双向链表的head,tail节点关系,清空无效节点* 3、挂起当前节点线程* @param arg* @throws InterruptedException*/private void doAcquireSharedInterruptibly(int arg)throws InterruptedException {//创建节点加入阻塞队列final Node node = addWaiter(Node.SHARED);boolean failed = true;try {for (;;) {//获得当前节点pre节点final Node p = node.predecessor();if (p == head) {int r = tryAcquireShared(arg);//返回锁的stateif (r >= 0) {setHeadAndPropagate(node, r);p.next = null; // help GCfailed = false;return;}}//重组双向链表,清空无效节点,挂起当前线程if (shouldParkAfterFailedAcquire(p, node) &&parkAndCheckInterrupt())throw new InterruptedException();}} finally {if (failed)cancelAcquire(node);}}

线程1、线程2、线程3、分别调用semaphore.acquire(),整个过程队列信息变化如下图:

(3)、释放令牌

 semaphore.release();

当调用semaphore.release() 方法时

1、线程会尝试释放一个令牌,释放令牌的过程也就是把同步队列的state修改为state=state+1的过程

2、释放令牌成功之后,同时会唤醒同步队列中的一个线程。

3、被唤醒的节点会重新尝试去修改state=state-1 的操作,如果state>=0则获取令牌成功,否则重新进入阻塞队列,挂起线程。

源码:

 /*** 释放令牌*/public void release() {sync.releaseShared(1);}

/***释放共享锁,同时会唤醒同步队列中的一个线程。* @param arg* @return*/public final boolean releaseShared(int arg) {//释放共享锁if (tryReleaseShared(arg)) {//唤醒所有共享节点线程doReleaseShared();return true;}return false;}

 /*** 唤醒同步队列中的一个线程*/private void doReleaseShared() {for (;;) {Node h = head;if (h != null && h != tail) {int ws = h.waitStatus;if (ws == Node.SIGNAL) {//是否需要唤醒后继节点if (!compareAndSetWaitStatus(h, Node.SIGNAL, 0))//修改状态为初始0continue;unparkSuccessor(h);//唤醒h.nex节点线程}else if (ws == 0 &&!compareAndSetWaitStatus(h, 0, Node.PROPAGATE));}if (h == head)                   // loop if head changedbreak;}}

继上面的图,当我们线程1调用semaphore.release(); 时候整个流程如下图:

编辑于 05-31 10:14

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/496649.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

使用代理时服务变量的变化

一、没有使用代理服务器的情况&#xff1a; REMOTE_ADDR 您的 IP HTTP_VIA 没数值或不显示 HTTP_X_FORWARDED_FOR 没数值或不显示 二、使用透明代理服务器的情况&#xff1a;Transparent Proxies REMOTE_ADDR 最后一个代理服务器 IP HTTP_VIA 代理服务器 …

SM2算法

文章目录前言一、SM2是什么&#xff1f;二、go语言实现前言 提示&#xff1a;以下是本篇文章正文内容&#xff0c;下面案例可供参考 一、SM2是什么&#xff1f; SM2是国家密码管理局于2010年12月17日发布的椭圆曲线公钥密码算法。 SM2算法和RSA算法都是公钥密码算法&#xf…

rocketmq 消息 自定义_跟我学RocketMQ[1-4]之消息消费及支持spring

博客地址:朝闻道​www.wuwenliang.net本文我将继续讲解如何使用DefaultMQPushConsumer对RocketMQ中的消息进行消费&#xff0c;同时在文章的第二部分将继续带领读者朋友对DefaultMQPushConsumer进行薄封装&#xff0c;让我们在Spring中更容易对消息进行消费。DefaultMQPushCons…

sklearn 逻辑回归Demo

逻辑回归案例 假设表示 基于上述情况&#xff0c;要使分类器的输出在[0,1]之间&#xff0c;可以采用假设表示的方法。 设 h θ ( x ) g ( θ T x ) h_θ (x)g(θ^T x) hθ​(x)g(θTx)&#xff0c; 其中 g ( z ) 1 ( 1 e − z ) g(z)\frac{1}{(1e^{−z} )} g(z)(1e−z)1​…

URL原理、URL编码、URL特殊字符、输入URL到页面显示

​From&#xff1a;http://blog.csdn.net/zmx729618/article/details/51381655 From&#xff1a;http://www.cnblogs.com/coco1s/p/5038412.html HTML URL 编码参考手册&#xff1a;https://www.w3cschool.cn/htmltags/html-urlencode.html http://www.w3school.com.cn/t…

记忆模糊、记忆泛化的关键分子开关被发现

来源&#xff1a;brainnews2018年3月12日&#xff0c;Nature Medicine杂志在线刊登了麻省总医院Amar Sahay研究组的最新重要工作&#xff0c;他们发现了一种细胞骨架蛋白Actin-binding LIM protein 3 (ABLIM3)&#xff0c;降低该蛋白的表达水平可以增强海马齿状回细胞&#xff…

240多个jQuery插件 (转)

概述 jQuery 是继 prototype 之后又一个优秀的 Javascript 框架。其宗旨是—写更少的代码,做更多的事情。它是轻量级的 js 库(压缩后只有21k) &#xff0c;这是其它的 js 库所不及的&#xff0c;它兼容 CSS3&#xff0c;还兼容各种浏览器&#xff08;IE 6.0, FF 1.5, Safari 2.…

Exchanger及其用法

01 Exchanger 作用 使两个线程之间进行数据传递。&#xff08;对是两个之间而不是三个或者更多个线程之间&#xff09; 02 常用方法 exchange&#xff08;&#xff09; 阻塞当前线程并等待其他线程来取得数据&#xff0c;若没有其他线程来取数据则一直等待。 exchange&…

SM3算法

文章目录前言一、SM3是什么&#xff1f;二、go语言实现前言 提示&#xff1a;以下是本篇文章正文内容&#xff0c;下面案例可供参考 一、SM3是什么&#xff1f; SM3是中华人民共和国政府采用的一种密码散列函数标准&#xff0c;由国家密码管理局于2010年12月17日发布。相关标…

2 如何设置窗口title_如何设置华为4G路由2的WiFi黑白名单【设置方法】

不想让自家的Wi-Fi被蹭网&#xff0c;除了将Wi-Fi隐藏起来&#xff0c;您还可以设置Wi-Fi黑白名单。如果您发现有人蹭网了&#xff0c;可以将蹭网设备直接加入黑名单&#xff0c;这样就可以禁止这个设备再连接到您的Wi-Fi。如果您将家人、朋友的设备加入了白名单&#xff0c;那…

复选框怎么点td选中_jQuery点击tr实现checkbox选中的方法

标题描述的有点不贴切&#xff0c;但希望大家能够明白&#xff0c;为了更形像的表达&#xff0c;我特意录制了一张GIF动画图片。我不知道实际开发中有没有用到这种效果&#xff0c;但我个人认为&#xff0c;这种方式更人性化&#xff0c;因为只要点到一行&#xff0c;就可以使C…

谷歌大脑AutoML最新进展:用进化算法发现神经网络架构

来源&#xff1a;AI中国大脑的进化进程持续已久&#xff0c;从5亿年前的蠕虫大脑到现如今各种现代结构。例如&#xff0c;人类的大脑可以完成各种各样的活动&#xff0c;其中许多活动都是毫不费力的。例如&#xff0c;分辨一个视觉场景中是否包含动物或建筑物对我们来说是微不足…

股票名词解释

开盘价&#xff1a;   是指当日开盘后该股票的第一笔交易成交的价格。如果开市后30分钟内无成交价&#xff0c;则以前日的收盘价作为开盘价。 收盘价&#xff1a;   指每天成交中最后一笔股票的价格&#xff0c;也就是收盘价格。 最高价&#xff1a;   是指当日所成交的…

linux 的 ip 命令 和 ifconfig 命令

From&#xff08;试试Linux下的ip命令&#xff0c;ifconfig已经过时了&#xff09;&#xff1a; https://linux.cn/article-3144-1.html From&#xff08;linux网络配置命令之ifconfig、ip和route&#xff09;&#xff1a; http://chrinux.blog.51cto.com/6466723/1188108 From…

SM4算法

文章目录前言一、SM4是什么&#xff1f;二、go语言实现前言 提示&#xff1a;以下是本篇文章正文内容&#xff0c;下面案例可供参考 一、SM4是什么&#xff1f; SM4.0&#xff08;原名SMS4.0&#xff09;是中华人民共和国政府采用的一种分组密码标准&#xff0c;由国家密码管…

Java并发编程实战~软件事务内存

很多同学反馈说&#xff0c;工作了挺长时间但是没有机会接触并发编程&#xff0c;实际上我们天天都在写并发程序&#xff0c;只不过并发相关的问题都被类似 Tomcat 这样的 Web 服务器以及 MySQL 这样的数据库解决了。尤其是数据库&#xff0c;在解决并发问题方面&#xff0c;可…

python list去重时间复杂度_List集合去重的一种方法 z

需要对一个List集合去重&#xff0c;情况是该集合中会出现多个Name属性值相同的&#xff0c;但是其他属性值不同的数据。在这种情况下&#xff0c;需求要只保留其中一个就好。我觉得遍历和HashSet都不是我想要的&#xff0c;便采用了一下方式定义Compare类&#xff0c;继承IEqu…

对于Office Live平台的思考

刚接触计算机编程的时候&#xff0c;脑子里想法比肚子里的墨水多得多&#xff0c;那时候想通过网络成立一个游戏开发团队&#xff0c;将不少人都很喜欢的一款FC游戏“重装机兵”&#xff08;Metal Max&#xff09;移植到电脑上来。当时的想法很激进也很宏大&#xff0c;我想的不…

中国学者用人工光感受器助失明小鼠复明

来源&#xff1a;《自然—通讯》中国研究人员在英国《自然通讯》杂志上发表报告说&#xff0c;他们通过在失明小鼠眼底植入一种新研发的人工光感受器&#xff0c;让它们的视觉得以恢复。如果这种技术发展成熟&#xff0c;未来或许能帮助因黄斑变性等疾病而视力下降或失明的患者…

PoW算法

文章目录前言一、PoW——工作量证明二、go语言简单案例前言 提示&#xff1a;以下是本篇文章正文内容&#xff0c;下面案例可供参考 一、PoW——工作量证明 ⚫ Proof-of-Work 简称 PoW&#xff0c;即为工作量证明 ⚫ 通过计算一个数值&#xff0c;使得拼揍上交易数据后内容的…