电脑知识|欧美黑人一区二区三区|软件|欧美黑人一级爽快片淫片高清|系统|欧美黑人狂野猛交老妇|数据库|服务器|编程开发|网络运营|知识问答|技术教程文章 - 好吧啦网

您的位置:首頁(yè)技術(shù)文章
文章詳情頁(yè)

分析Java并發(fā)編程之信號(hào)量Semaphore

瀏覽:4日期:2022-08-10 09:43:53
目錄一、認(rèn)識(shí)Semaphore1.1、Semaphore 的使用場(chǎng)景1.2、Semaphore 使用1.3、Semaphore 信號(hào)量的模型二、Semaphore 深入理解2.1、Semaphore 基本屬性2.2、Semaphore 的公平性和非公平性2.3、其他 Semaphore 方法一、認(rèn)識(shí)Semaphore1.1、Semaphore 的使用場(chǎng)景

Semaphore 的使用場(chǎng)景主要用于流量控制,比如數(shù)據(jù)庫(kù)連接,同時(shí)使用的數(shù)據(jù)庫(kù)連接會(huì)有數(shù)量限制,數(shù)據(jù)庫(kù)連接不能超過(guò)一定的數(shù)量,當(dāng)連接到達(dá)了限制數(shù)量后,后面的線程只能排隊(duì)等前面的線程釋放數(shù)據(jù)庫(kù)連接后才能獲得數(shù)據(jù)庫(kù)連接。

再比如交通公路上的紅綠燈,綠燈亮起時(shí)只能讓 100 輛車通過(guò),紅燈亮起不允許車輛通過(guò)。

再比如停車場(chǎng)的場(chǎng)景中,一個(gè)停車場(chǎng)有有限數(shù)量的車位,同時(shí)能夠容納多少臺(tái)車,車位滿了之后只有等里面的車離開(kāi)停車場(chǎng)外面的車才可以進(jìn)入。

1.2、Semaphore 使用

下面我們就來(lái)模擬一下停車場(chǎng)的業(yè)務(wù)場(chǎng)景:在進(jìn)入停車場(chǎng)之前會(huì)有一個(gè)提示牌,上面顯示著停車位還有多少,當(dāng)車位為 0 時(shí),不能進(jìn)入停車場(chǎng),當(dāng)車位不為 0 時(shí),才會(huì)允許車輛進(jìn)入停車場(chǎng)。所以停車場(chǎng)有幾個(gè)關(guān)鍵因素:停車場(chǎng)車位的總?cè)萘浚?dāng)一輛車進(jìn)入時(shí),停車場(chǎng)車位的總?cè)萘?- 1,當(dāng)一輛車離開(kāi)時(shí),總?cè)萘?+ 1,停車場(chǎng)車位不足時(shí),車輛只能在停車場(chǎng)外等待。

public class CarParking { private static Semaphore semaphore = new Semaphore(10); public static void main(String[] args){for(int i = 0;i< 100;i++){ Thread thread = new Thread(new Runnable() {@Overridepublic void run() { System.out.println('歡迎 ' + Thread.currentThread().getName() + ' 來(lái)到停車場(chǎng)'); // 判斷是否允許停車 if(semaphore.availablePermits() == 0) {System.out.println('車位不足,請(qǐng)耐心等待'); } try {// 嘗試獲取semaphore.acquire();System.out.println(Thread.currentThread().getName() + ' 進(jìn)入停車場(chǎng)');Thread.sleep(new Random().nextInt(10000));// 模擬車輛在停車場(chǎng)停留的時(shí)間System.out.println(Thread.currentThread().getName() + ' 駛出停車場(chǎng)');semaphore.release(); } catch (InterruptedException e) {e.printStackTrace(); }} }, i + '號(hào)車'); thread.start();} }}

在上面這段代碼中,我們給出了 Semaphore 的初始容量,也就是只有 10 個(gè)車位,我們用這 10 個(gè)車位來(lái)控制 100 輛車的流量,所以結(jié)果和我們預(yù)想的很相似,即大部分車都在等待狀態(tài)。但是同時(shí)仍允許一些車駛?cè)胪\噲?chǎng),駛?cè)胪\噲?chǎng)的車輛,就會(huì) semaphore.acquire 占用一個(gè)車位,駛出停車場(chǎng)時(shí),就會(huì) semaphore.release 讓出一個(gè)車位,讓后面的車再次駛?cè)搿?/p>1.3、Semaphore 信號(hào)量的模型

上面代碼雖然比較簡(jiǎn)單,但是卻能讓我們了解到一個(gè)信號(hào)量模型的五臟六腑。下面是一個(gè)信號(hào)量的模型:

分析Java并發(fā)編程之信號(hào)量Semaphore

來(lái)解釋一下 Semaphore ,Semaphore 有一個(gè)初始容量,這個(gè)初始容量就是 Semaphore 所能夠允許的信號(hào)量。在調(diào)用 Semaphore 中的 acquire 方法后,Semaphore 的容量 -1,相對(duì)的在調(diào)用 release 方法后,Semaphore 的容量 + 1,在這個(gè)過(guò)程中,計(jì)數(shù)器一直在監(jiān)控 Semaphore 數(shù)量的變化,等到流量超過(guò) Semaphore 的容量后,多余的流量就會(huì)放入等待隊(duì)列中進(jìn)行排隊(duì)等待。等到 Semaphore 的容量允許后,方可重新進(jìn)入。

Semaphore 所控制的流量其實(shí)就是一個(gè)個(gè)的線程,因?yàn)椴l(fā)工具最主要的研究對(duì)象就是線程。

它的工作流程如下

分析Java并發(fā)編程之信號(hào)量Semaphore

這幅圖應(yīng)該很好理解吧,這里就不再過(guò)多解釋啦。

二、Semaphore 深入理解

在了解 Semaphore 的基本使用和 Semaphore 的模型后,下面我們還是得從源碼來(lái)和你聊一聊 Semaphore 的種種細(xì)節(jié)問(wèn)題,因?yàn)槲覍懳恼伦詈诵牡臇|西就是想讓我的讀者 了解 xxx,看這一篇就夠了,這是我寫文章的追求,好了話不多說(shuō),源碼走起來(lái)!

2.1、Semaphore 基本屬性

Semaphore 中只有一個(gè)屬性

private final Sync sync;

Sync 是 Semaphore 的同步實(shí)現(xiàn),Semaphore 保證線程安全性的方式和 ReentrantLock 、CountDownLatch 類似,都是繼承于 AQS 的實(shí)現(xiàn)。同樣的,這個(gè) Sync 也是繼承于 AbstractQueuedSynchronizer 的一個(gè)變量,也就是說(shuō),聊 Semaphore 也繞不開(kāi) AQS,所以說(shuō) AQS 真的太重要了。

2.2、Semaphore 的公平性和非公平性

那么我們進(jìn)入 Sync 內(nèi)部看看它實(shí)現(xiàn)了哪些方法

abstract static class Sync extends AbstractQueuedSynchronizer { private static final long serialVersionUID = 1192457210091910933L; Sync(int permits) { setState(permits); } final int getPermits() { return getState(); } final int nonfairTryAcquireShared(int acquires) { for (;;) { int available = getState(); int remaining = available - acquires; if (remaining < 0 || compareAndSetState(available, remaining))return remaining; } } protected final boolean tryReleaseShared(int releases) { for (;;) { int current = getState(); int next = current + releases; if (next < current) // overflowthrow new Error('Maximum permit count exceeded'); if (compareAndSetState(current, next))return true; } } final void reducePermits(int reductions) { for (;;) { int current = getState(); int next = current - reductions; if (next > current) // underflowthrow new Error('Permit count underflow'); if (compareAndSetState(current, next))return; } } final int drainPermits() { for (;;) { int current = getState(); if (current == 0 || compareAndSetState(current, 0))return current; } }}

首先是 Sync 的初始化,內(nèi)部調(diào)用了 setState 并傳遞了 permits ,我們知道,AQS 中的 State 其實(shí)就是同步狀態(tài)的值,而 Semaphore 的這個(gè) permits 就是代表了許可的數(shù)量。

getPermits 其實(shí)就是調(diào)用了 getState 方法獲取了一下線程同步狀態(tài)值。后面的 nonfairTryAcquireShared 方法其實(shí)是在 Semaphore 中構(gòu)造了 NonfairSync 中的 tryAcquireShared 調(diào)用的

分析Java并發(fā)編程之信號(hào)量Semaphore

這里需要提及一下什么是 NonfairSync,除了 NonfairSync 是不是還有 FairSync 呢?查閱 JDK 源碼發(fā)現(xiàn)確實(shí)有。

那么這里的 FairSync 和 NonfairSync 都代表了什么?為什么會(huì)有這兩個(gè)類呢?

事實(shí)上,Semaphore 就像 ReentrantLock 一樣,也存在“公平”和'不公平'兩種,默認(rèn)情況下 Semaphore 是一種不公平的信號(hào)量

分析Java并發(fā)編程之信號(hào)量Semaphore

Semaphore 的不公平意味著它不會(huì)保證線程獲得許可的順序,Semaphore 會(huì)在線程等待之前為調(diào)用 acquire 的線程分配一個(gè)許可,擁有這個(gè)許可的線程會(huì)自動(dòng)將自己置于線程等待隊(duì)列的頭部。

當(dāng)這個(gè)參數(shù)為 true 時(shí),Semaphore 確保任何調(diào)用 acquire 的方法,都會(huì)按照先入先出的順序來(lái)獲取許可。

final int nonfairTryAcquireShared(int acquires) { for (;;) { // 獲取同步狀態(tài)值 int available = getState(); // state 的值 - 當(dāng)前線程需要獲取的信號(hào)量(通常默認(rèn)是 -1),只有 // remaining > 0 才表示可以獲取。 int remaining = available - acquires; // 先判斷是否小于 0 ,如果小于 0 則表示無(wú)法獲取,如果是正數(shù) // 就需要使用 CAS 判斷內(nèi)存值和同步狀態(tài)值是否一致,然后更新為同步狀態(tài)值 - 1 if (remaining < 0 ||compareAndSetState(available, remaining)) return remaining; }}

分析Java并發(fā)編程之信號(hào)量Semaphore

從上面這幅源碼對(duì)比圖可以看到,NonfairSync 和 FairSync 最大的區(qū)別就在于 tryAcquireShared 方法的區(qū)別。

NonfairSync 版本中,是不會(huì)管當(dāng)前等待隊(duì)列中是否有排隊(duì)許可的,它會(huì)直接判斷信號(hào)許可量和 CAS 方法的可行性。

FairSync 版本中,它首先會(huì)判斷是否有許可進(jìn)行排隊(duì),如果有的話就直接獲取失敗。

這時(shí)候可能就會(huì)有讀者問(wèn)了,你上面說(shuō)公平性和非公平性的區(qū)別一直針對(duì)的是 acquire 方法來(lái)說(shuō)的,怎么現(xiàn)在他們兩個(gè)主要的區(qū)別在于 tryAcquireShared 方法呢?

別急,讓我們進(jìn)入到 acquire 方法一探究竟

分析Java并發(fā)編程之信號(hào)量Semaphore

可以看到,在 acquire 方法中,會(huì)調(diào)用 tryAcquireShared 方法,根據(jù)其返回值判斷是否調(diào)用 doAcquireSharedInterruptibly 方法。

這里需要注意下,acquire 方法具有阻塞性,而 tryAcquire 方法不具有阻塞性。

這也就是說(shuō),調(diào)用 acquire 方法如果獲取不到許可,那么 Semaphore 會(huì)阻塞,直到有可用的許可。而 tryAcquire 方法如果獲取不到許可會(huì)直接返回 false。

這里還需要注意下 acquireUninterruptibly 方法,其他 acquire 的相關(guān)方法要么是非阻塞,要么是阻塞可中斷,而 acquireUninterruptibly 方法不僅在沒(méi)有許可的情況下執(zhí)著的等待,而且也不會(huì)中斷,使用這個(gè)方法時(shí)需要注意,這個(gè)方法很容易在出現(xiàn)大規(guī)模線程阻塞而導(dǎo)致 Java 進(jìn)程出現(xiàn)假死的情況。

有獲取許可相對(duì)應(yīng)的就有釋放許可,但是釋放許可不會(huì)區(qū)分到底是公平釋放還是非公平釋放。不管方式如何都是釋放一個(gè)許可給 Semaphore ,同樣的 Semaphore 中的許可數(shù)量會(huì)增加。

分析Java并發(fā)編程之信號(hào)量Semaphore

在上圖中調(diào)用 tryReleaseShared 判斷是否能進(jìn)行釋放后,再會(huì)調(diào)用 AQS 中的 releasedShared 方法進(jìn)行釋放。

分析Java并發(fā)編程之信號(hào)量Semaphore

上面這個(gè)釋放流程只是釋放一個(gè)許可,除此之外,還可以釋放多個(gè)許可

public void release(int permits) { if (permits < 0) throw new IllegalArgumentException(); sync.releaseShared(permits);}

后面這個(gè) releaseShared 的釋放流程和上面的釋放流程一致。

2.3、其他 Semaphore 方法

除了上面基本的 acquire 和 release 相關(guān)方法外,我們也要了解一下 Semaphore 的其他方法。Semaphore 的其他方法比較少,只有下面這幾個(gè):

drainPermits : 獲取并退還所有立即可用的許可,其實(shí)相當(dāng)于使用 CAS 方法把內(nèi)存值置為 0 reducePermits:和 nonfairTryAcquireShared 方法類似,只不過(guò) nonfairTryAcquireShared 是使用 CAS 使內(nèi)存值 + 1,而 reducePermits 是使內(nèi)存值 - 1 。 isFair:對(duì) Semaphore 許可的爭(zhēng)奪是采用公平還是非公平的方式,對(duì)應(yīng)到內(nèi)部的實(shí)現(xiàn)就是 FairSync 和 NonfairSync。 hasQueuedThreads:當(dāng)前是否有線程由于要獲取 Semaphore 許可而進(jìn)入阻塞。 getQueuedThreads:返回一個(gè)包含了等待獲取許可的線程集合。 getQueueLength:獲取正在排隊(duì)而進(jìn)入阻塞狀態(tài)的線程個(gè)數(shù)

以上就是分析Java并發(fā)編程之信號(hào)量Semaphore的詳細(xì)內(nèi)容,更多關(guān)于Java并發(fā)編程 信號(hào)量Semaphore的資料請(qǐng)關(guān)注好吧啦網(wǎng)其它相關(guān)文章!

標(biāo)簽: Java
相關(guān)文章:
主站蜘蛛池模板: 润滑油加盟_润滑油厂家_润滑油品牌-深圳市沃丹润滑科技有限公司 琉璃瓦-琉璃瓦厂家-安徽盛阳新型建材科技有限公司 | [品牌官网]贵州遵义双宁口腔连锁_贵州遵义牙科医院哪家好_种植牙_牙齿矫正_原华美口腔 | 透平油真空滤油机-变压器油板框滤油机-滤油车-华之源过滤设备 | EFM 022静电场测试仪-套帽式风量计-静电平板监测器-上海民仪电子有限公司 | 顶呱呱交易平台-行业领先的公司资产交易服务平台 | 玉米深加工机械,玉米加工设备,玉米加工机械等玉米深加工设备制造商-河南成立粮油机械有限公司 | 艺术涂料_进口艺术涂料_艺术涂料加盟_艺术涂料十大品牌 -英国蒙太奇艺术涂料 | 嘉兴泰东园林景观工程有限公司_花箱护栏 | 减速机电机一体机_带电机减速器一套_德国BOSERL电动机与减速箱生产厂家 | 聚丙烯酰胺_阴离子_阳离子「用量少」巩义亿腾厂家直销,售后无忧 聚合甘油__盐城市飞龙油脂有限公司 | 厂厂乐-汇聚海量采购信息的B2B微营销平台-厂厂乐官网 | 山东包装,山东印刷厂,济南印刷厂-济南富丽彩印刷有限公司 | 气象监测系统_气象传感器_微型气象仪_气象环境监测仪-山东风途物联网 | 上海网站建设-上海网站制作-上海网站设计-上海做网站公司-咏熠软件 | 不锈钢管件(不锈钢弯头,不锈钢三通,不锈钢大小头),不锈钢法兰「厂家」-浙江志通管阀 | 电主轴,车床电磨头,变频制动电机-博山鸿达特种电机 | 二手色谱仪器,十万分之一分析天平,蒸发光检测器,电位滴定仪-湖北捷岛科学仪器有限公司 | 宿松新闻网 宿松网|宿松在线|宿松门户|安徽宿松(直管县)|宿松新闻综合网站|宿松官方新闻发布 | 南京蜂窝纸箱_南京木托盘_南京纸托盘-南京博恒包装有限公司 | 超声波气象站_防爆气象站_空气质量监测站_负氧离子检测仪-风途物联网 | 鹤壁创新仪器公司-全自动量热仪,定硫仪,煤炭测硫仪,灰熔点测定仪,快速自动测氢仪,工业分析仪,煤质化验仪器 | 减速机电机一体机_带电机减速器一套_德国BOSERL电动机与减速箱生产厂家 | 蚂蚁分类信息系统 - PHP同城分类信息系统 - MayiCMS | 贴片电感_贴片功率电感_贴片绕线电感_深圳市百斯特电子有限公司 贴片电容代理-三星电容-村田电容-风华电容-国巨电容-深圳市昂洋科技有限公司 | 新能源汽车教学设备厂家报价[汽车教学设备运营18年]-恒信教具 | 钢托盘,钢制托盘,立库钢托盘,金属托盘制造商_南京飞天金属制品实业有限公司 | 广东恩亿梯电源有限公司【官网】_UPS不间断电源|EPS应急电源|模块化机房|电动汽车充电桩_UPS电源厂家(恩亿梯UPS电源,UPS不间断电源,不间断电源UPS) | 皮带机_移动皮带机_大倾角皮带机_皮带机厂家 - 新乡市国盛机械设备有限公司 | 美侍宠物-专注宠物狗及宠物猫训练|喂养|医疗|繁育|品种|价格 | 球磨机 选矿球磨机 棒磨机 浮选机 分级机 选矿设备厂家 | 首页|专注深圳注册公司,代理记账报税,注册商标代理,工商变更,企业400电话等企业一站式服务-慧用心 | 地图标注|微信高德百度地图标注|地图标记-做地图[ZuoMap.com] | MES系统-WMS系统-MES定制开发-制造执行MES解决方案-罗浮云计算 | 天津试验仪器-电液伺服万能材料试验机,恒温恒湿标准养护箱,水泥恒应力压力试验机-天津鑫高伟业科技有限公司 | 365文案网_全网创意文案句子素材站| 塑料熔指仪-塑料熔融指数仪-熔体流动速率试验机-广东宏拓仪器科技有限公司 | 航空铝型材,7系铝型材挤压,硬质阳*氧化-余润铝制品 | 真空粉体取样阀,电动楔式闸阀,电动针型阀-耐苛尔(上海)自动化仪表有限公司 | 光伏家 - 太阳能光伏发电_分布式光伏发电_太阳能光伏网 | 北京森语科技有限公司-模型制作专家-展览展示-沙盘模型设计制作-多媒体模型软硬件开发-三维地理信息交互沙盘 | 大行程影像测量仪-探针型影像测量仪-增强型影像测量仪|首丰百科 大通天成企业资质代办_承装修试电力设施许可证_增值电信业务经营许可证_无人机运营合格证_广播电视节目制作许可证 |