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

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

詳解Java 信號(hào)量Semaphore

瀏覽:29日期:2022-08-24 17:41:31

Semaphore也是一個(gè)同步器,和前面兩篇說的CountDownLatch和CyclicBarrier不同,這是遞增的,初始化的時(shí)候可以指定一個(gè)值,但是不需要知道需要同步的線程個(gè)數(shù),只需要在同步的地方調(diào)用acquire方法時(shí)指定需要同步的線程個(gè)數(shù);

一.簡(jiǎn)單使用

同步兩個(gè)子線程,只有其中兩個(gè)子線程執(zhí)行完畢,主線程才會(huì)執(zhí)行:

package com.example.demo.study;import java.util.concurrent.ExecutorService;import java.util.concurrent.Executors;import java.util.concurrent.Semaphore;public class Study0217 { //創(chuàng)建一個(gè)信號(hào)量的實(shí)例,信號(hào)量初始值為0 static Semaphore semaphore = new Semaphore(0); public static void main(String[] args) throws Exception { ExecutorService pool = Executors.newFixedThreadPool(3); pool.submit(()->{ System.out.println('Thread1---start'); //信號(hào)量加一 semaphore.release(); });pool.submit(()->{ System.out.println('Thread2---start'); //信號(hào)量加一 semaphore.release(); }); pool.submit(()->{ System.out.println('Thread3---start'); //信號(hào)量加一 semaphore.release(); }); //等待兩個(gè)子線程執(zhí)行完畢就放過,必須要信號(hào)量等于2才放過 semaphore.acquire(2); System.out.println('兩個(gè)子線程執(zhí)行完畢');//關(guān)閉線程池,正在執(zhí)行的任務(wù)繼續(xù)執(zhí)行 pool.shutdown(); }}

詳解Java 信號(hào)量Semaphore

這個(gè)信號(hào)量也可以復(fù)用,類似CyclicBarrier:

package com.example.demo.study;import java.util.concurrent.ExecutorService;import java.util.concurrent.Executors;import java.util.concurrent.Semaphore;public class Study0217 { //創(chuàng)建一個(gè)信號(hào)量的實(shí)例,信號(hào)量初始值為0 static Semaphore semaphore = new Semaphore(0); public static void main(String[] args) throws Exception { ExecutorService pool = Executors.newFixedThreadPool(3); pool.submit(()->{ System.out.println('Thread1---start'); //信號(hào)量加一 semaphore.release(); });pool.submit(()->{ System.out.println('Thread2---start'); //信號(hào)量加一 semaphore.release(); });//等待兩個(gè)子線程執(zhí)行完畢就放過,必須要信號(hào)量等于2才放過 semaphore.acquire(2); System.out.println('子線程1,2執(zhí)行完畢');pool.submit(()->{ System.out.println('Thread3---start'); //信號(hào)量加一 semaphore.release(); }); pool.submit(()->{ System.out.println('Thread4---start'); //信號(hào)量加一 semaphore.release(); });semaphore.acquire(2); System.out.println('子線程3,4執(zhí)行完畢');//關(guān)閉線程池,正在執(zhí)行的任務(wù)繼續(xù)執(zhí)行 pool.shutdown(); }}

詳解Java 信號(hào)量Semaphore

二.信號(hào)量原理 

看看下面這個(gè)圖,可以知道信號(hào)量Semaphore還是根據(jù)AQS實(shí)現(xiàn)的,內(nèi)部有個(gè)Sync工具類操作AQS,還分為公平策略和非公平策略;

詳解Java 信號(hào)量Semaphore

構(gòu)造器:

//默認(rèn)是非公平策略public Semaphore(int permits) { sync = new NonfairSync(permits);}//可以根據(jù)第二個(gè)參數(shù)選擇是公平策略還是非公平策略public Semaphore(int permits, boolean fair) { sync = fair ? new FairSync(permits) : new NonfairSync(permits);}

acquire(int permits)方法:

public void acquire(int permits) throws InterruptedException { if (permits < 0) throw new IllegalArgumentException(); sync.acquireSharedInterruptibly(permits);}//AQS中的方法public final void acquireSharedInterruptibly(int arg) throws InterruptedException { if (Thread.interrupted()) throw new InterruptedException(); //這里根據(jù)子類是公平策略還是非公平策略 if (tryAcquireShared(arg) < 0) //獲取失敗會(huì)進(jìn)入這里,將線程放入阻塞隊(duì)列,然后再嘗試,還是失敗的話就調(diào)用park方法掛起當(dāng)前線程 doAcquireSharedInterruptibly(arg);}//非公平策略protected int tryAcquireShared(int acquires) { return nonfairTryAcquireShared(acquires);}final int nonfairTryAcquireShared(int acquires) { //一個(gè)無限循環(huán),獲取state剩余的信號(hào)量,因?yàn)槊空{(diào)用一次release()方法的話,信號(hào)量就會(huì)加一,這里將 //最新的信號(hào)量減去傳進(jìn)來的參數(shù)比較,比如有兩個(gè)線程,其中一個(gè)線程已經(jīng)調(diào)用了release方法,然后調(diào)用acquire(2)方法,那么 //這里remaining的值就是-1,返回-1,然后當(dāng)前線程就會(huì)被丟到阻塞隊(duì)列中去了;如果另外一個(gè)線程也調(diào)用了release方法, //那么此時(shí)的remaining==0,所以在這里的if中會(huì)調(diào)用CAS將0設(shè)置到state // for (;;) { int available = getState(); int remaining = available - acquires; if (remaining < 0 || compareAndSetState(available, remaining)) return remaining; }}//公平策略//和上面非公平差不多,只不過這里會(huì)查看阻塞隊(duì)列中當(dāng)前節(jié)點(diǎn)前面有沒有前驅(qū)節(jié)點(diǎn),有的話直接返回-1,//就會(huì)把當(dāng)前線程丟到阻塞隊(duì)列中阻塞去了,沒有前驅(qū)節(jié)點(diǎn)的話,就跟非公平模式一樣的了protected int tryAcquireShared(int acquires) { for (;;) { if (hasQueuedPredecessors()) return -1; int available = getState(); int remaining = available - acquires; if (remaining < 0 ||compareAndSetState(available, remaining)) return remaining; }}

再看看release(int permits)方法:

//這個(gè)方法的作用就是將信號(hào)量加一public void release(int permits) { if (permits < 0) throw new IllegalArgumentException(); sync.releaseShared(permits);}//AQS中方法public final boolean releaseShared(int arg) { //tryReleaseShared嘗試釋放資源 if (tryReleaseShared(arg)) { //釋放資源成功就調(diào)用park方法喚醒喚醒AQS隊(duì)列中最前面的節(jié)點(diǎn)中的線程 doReleaseShared(); return true; } return false;}protected final boolean tryReleaseShared(int releases) { //一個(gè)無限循環(huán),獲取state,然后加上傳進(jìn)去的參數(shù),如果新的state的值小于舊的state,說明已經(jīng)超過了state的最大值,溢出了 //沒有溢出的話,就用CAS更新state的值 for (;;) { int current = getState(); int next = current + releases; if (next < current) // overflow throw new Error('Maximum permit count exceeded'); if (compareAndSetState(current, next)) return true; }}private void doReleaseShared() { for (;;) { Node h = head; if (h != null && h != tail) { int ws = h.waitStatus; //ws==Node.SIGNAL表示節(jié)點(diǎn)中線程需要被喚醒 if (ws == Node.SIGNAL) {if (!compareAndSetWaitStatus(h, Node.SIGNAL, 0)) continue; // loop to recheck cases//調(diào)用阻塞隊(duì)列中線程的unpark方法喚醒線程unparkSuccessor(h); } //ws == 0表示節(jié)點(diǎn)中線程是初始狀態(tài) else if (ws == 0 && !compareAndSetWaitStatus(h, 0, Node.PROPAGATE))continue;// loop on failed CAS }if (h == head) // loop if head changed break; }}

以最上面的例子簡(jiǎn)單說一下,其實(shí)不是很難,首先線程1和線程2分別去調(diào)用release方法,這個(gè)方法里面會(huì)將AQS中的state加一,但是在執(zhí)行這個(gè)操作之前,主線程肯定會(huì)先到acquire(2),在這個(gè)方法里面,假如默認(rèn)使用非公平策略,首先獲取當(dāng)前的信號(hào)量state(state的初始值是0),用當(dāng)前信號(hào)量減去2,如果小于0,那么當(dāng)前主線程就會(huì)丟到AQS隊(duì)列中阻塞;

這個(gè)時(shí)候線程1的release方法執(zhí)行了,于是就把信號(hào)量state加一(此時(shí)state==1),CAS更新state為一,成功的話,就調(diào)用doReleaseShared()方法喚醒AQS阻塞隊(duì)列中最先掛起的線程(這里就是因?yàn)檎{(diào)用acquire方法而阻塞的主線程),主線程喚醒之后又會(huì)去獲取最新的信號(hào)量,與2比較,發(fā)現(xiàn)還是小于0,于是又會(huì)阻塞;

線程2此時(shí)的release方法執(zhí)行完成,重復(fù)線程一的操作,主線程喚醒之后(此時(shí)state==2),又去獲取最新的信號(hào)量發(fā)現(xiàn)是2,減去acquire方法的參數(shù)2等于0,于是就用CAS更新state的值,然后acquire方法也就執(zhí)行完畢,主線程繼續(xù)執(zhí)行后面的代碼;

其實(shí)信號(hào)量還是很有意思的,記得在項(xiàng)目里,有人利用信號(hào)量實(shí)現(xiàn)了一個(gè)故障隔離,什么時(shí)候我可以把整理之后的代碼貼出來分享一下,還是很有意思的,就跟springcloud的熔斷機(jī)制差不多,場(chǎng)景是:比如你在service的一個(gè)方法調(diào)用第三方的接口,你不知道調(diào)不調(diào)得通,而且你不希望每次前端過來都會(huì)去調(diào)用,比如當(dāng)調(diào)用失敗的次數(shù)超過100次,那么五分鐘之后才會(huì)再去實(shí)際調(diào)用這個(gè)第三方服務(wù)!這五分鐘內(nèi)前調(diào)用這個(gè)服務(wù),就會(huì)觸發(fā)我們這個(gè)故障隔離的機(jī)制,向前端返回一個(gè)特定的錯(cuò)誤碼和錯(cuò)誤信息!

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

標(biāo)簽: Java
相關(guān)文章:
主站蜘蛛池模板: 杰福伦_磁致伸缩位移传感器_线性位移传感器-意大利GEFRAN杰福伦-河南赉威液压科技有限公司 | 真空泵维修保养,普发,阿尔卡特,荏原,卡西亚玛,莱宝,爱德华干式螺杆真空泵维修-东莞比其尔真空机电设备有限公司 | 镀锌角钢_槽钢_扁钢_圆钢_方矩管厂家_镀锌花纹板-海邦钢铁(天津)有限公司 | 玻纤土工格栅_钢塑格栅_PP焊接_单双向塑料土工格栅_复合防裂布厂家_山东大庚工程材料科技有限公司 | 数码听觉统合训练系统-儿童感觉-早期言语评估与训练系统-北京鑫泰盛世科技发展有限公司 | 磁力抛光机_磁力研磨机_磁力去毛刺机-冠古设备厂家|维修|租赁【官网】 | 上海公司注册-代理记账-招投标审计-上海昆仑扇财税咨询有限公司 上海冠顶工业设备有限公司-隧道炉,烘箱,UV固化机,涂装设备,高温炉,工业机器人生产厂家 | 葡萄酒灌装机-食用油灌装机-液体肥灌装设备厂家_青州惠联灌装机械 | 橡胶膜片,夹布膜片,橡胶隔膜密封,泵阀设备密封膜片-衡水汉丰橡塑科技公司网站 | 杭州成人高考_浙江省成人高考网上报名 | 顺辉瓷砖-大国品牌-中国顺辉 | 螺纹三通快插接头-弯通快插接头-宁波舜驰气动科技有限公司 | 电主轴,车床电磨头,变频制动电机-博山鸿达特种电机 | 青岛空压机,青岛空压机维修/保养,青岛空压机销售/出租公司,青岛空压机厂家电话 | 书法培训-高考书法艺考培训班-山东艺霖书法培训凭实力挺进央美 | 100国际学校招生 - 专业国际学校择校升学规划 | 东莞爱加真空科技有限公司-进口真空镀膜机|真空镀膜设备|Polycold维修厂家 | 无锡网站建设_小程序制作_网站设计公司_无锡网络公司_网站制作 | 昆明网络公司|云南网络公司|昆明网站建设公司|昆明网页设计|云南网站制作|新媒体运营公司|APP开发|小程序研发|尽在昆明奥远科技有限公司 | 【孔氏陶粒】建筑回填陶粒-南京/合肥/武汉/郑州/重庆/成都/杭州陶粒厂家 | 杭州标识标牌|文化墙|展厅|导视|户内外广告|发光字|灯箱|铭阳制作公司 - 杭州标识标牌|文化墙|展厅|导视|户内外广告|发光字|灯箱|铭阳制作公司 | 纸塑分离机-纸塑分离清洗机设备-压力筛-碎浆机厂家金双联环保 | 招商帮-一站式网络营销服务|互联网整合营销|网络推广代运营|信息流推广|招商帮企业招商好帮手|搜索营销推广|短视视频营销推广 | 医用空气消毒机-医用管路消毒机-工作服消毒柜-成都三康王 | 冰晶石|碱性嫩黄闪蒸干燥机-有机垃圾烘干设备-草酸钙盘式干燥机-常州市宝康干燥 | 欧美日韩国产一区二区三区不_久久久久国产精品无码不卡_亚洲欧洲美洲无码精品AV_精品一区美女视频_日韩黄色性爱一级视频_日本五十路人妻斩_国产99视频免费精品是看4_亚洲中文字幕无码一二三四区_国产小萍萍挤奶喷奶水_亚洲另类精品无码在线一区 | 运动木地板_体育木地板_篮球馆木地板_舞台木地板-实木运动地板厂家 | MTK核心板|MTK开发板|MTK模块|4G核心板|4G模块|5G核心板|5G模块|安卓核心板|安卓模块|高通核心板-深圳市新移科技有限公司 | 搜木网 - 木业全产业链交易平台,免费搜货、低价买货! | 全自动端子机|刺破式端子压接机|全自动双头沾锡机|全自动插胶壳端子机-东莞市傅氏兄弟机械设备有限公司 | 苏州注册公司_苏州代理记账_苏州工商注册_苏州代办公司-恒佳财税 | 净水器代理,净水器招商,净水器加盟-FineSky德国法兹全屋净水 | 杭州画室_十大画室_白墙画室_杭州美术培训_国美附中培训_附中考前培训_升学率高的画室_美术中考集训美术高考集训基地 | 广州食堂承包_广州团餐配送_广州堂食餐饮服务公司 - 旺记餐饮 | 通辽信息港 - 免费发布房产、招聘、求职、二手、商铺等信息 www.tlxxg.net | 大数据营销公司_舆情监测软件_上海SEO公司-文军营销官网 | 【甲方装饰】合肥工装公司-合肥装修设计公司,专业从事安徽办公室、店面、售楼部、餐饮店、厂房装修设计服务 | 维泰克Veertek-锂电池微短路检测_锂电池腐蚀检测_锂电池漏液检测 | 礼仪庆典公司,礼仪策划公司,庆典公司,演出公司,演艺公司,年会酒会,生日寿宴,动工仪式,开工仪式,奠基典礼,商务会议,竣工落成,乔迁揭牌,签约启动-东莞市开门红文化传媒有限公司 | 招商帮-一站式网络营销服务|搜索营销推广|信息流推广|短视视频营销推广|互联网整合营销|网络推广代运营|招商帮企业招商好帮手 | 烟气在线监测系统_烟气在线监测仪_扬尘检测仪_空气质量监测站「山东风途物联网」 |