網(wǎng)站首頁 編程語言 正文
目錄
1.Semaphore介紹
1.1 限流操作實(shí)戰(zhàn)
1.2 Semaphore源碼解析
?2. countDownLatch介紹
2.1 多個(gè)線程等待實(shí)戰(zhàn)
?2.2 主線程等待
2.3 源碼分析
1.Semaphore介紹
semaphorer(信號(hào)量),是一個(gè)基于AQS框架實(shí)現(xiàn)的工具類,也是操作系統(tǒng)PV操作在java中的實(shí)現(xiàn)。通過發(fā)放許可來控制線程,只有拿到許可的線程才能執(zhí)行代碼,常用于限流操作。
PV操作是一種操作系統(tǒng)實(shí)現(xiàn)進(jìn)程互斥與同步的有效方法:P表示通過,V表示釋放。
P操作:S-1=X,如果X>=0線程執(zhí)行,如果小于0放入等待隊(duì)列中。
V操作:S+1=X,如果X>=0線程執(zhí)行,如果小于0從等待隊(duì)列釋放一個(gè)等待線程。
構(gòu)造器(默認(rèn)非公平鎖,也有公平鎖實(shí)現(xiàn)):
public Semaphore(int permits) { sync = new NonfairSync(permits); }public Semaphore(int permits, boolean fair) { sync = fair ? new FairSync(permits) : new NonfairSync(permits); }
常用的方法:
acquire()獲取許可拿到共享鎖
tryacquire()嘗試獲取鎖,獲取到鎖返回true,沒有返回false
release()釋放許可
1.1 限流操作實(shí)戰(zhàn)
模擬限流操作
1. 5個(gè)線程發(fā)送3個(gè)許可。
2. 10個(gè)核心線程發(fā)送5個(gè)許可。
import java.util.concurrent.Semaphore;
/**
* 限流操作
*/
public class SemaphoreTest {
private static Semaphore semaphore = new Semaphore(3);//發(fā)放三個(gè)許可
public static void main(String[] args) throws Exception {
//執(zhí)行5個(gè)線程
for(int i=0;i<5;i++){
new Thread(()->{
try{
semaphore.acquire();
System.out.println(Thread.currentThread().getName()+"開始購票");
Thread.sleep(5000);
System.out.println(Thread.currentThread().getName()+"購票成功");
}catch (InterruptedException e) {
e.printStackTrace();
}finally {
semaphore.release();
}
}).start();
}
}
}
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.Semaphore;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
/**
* 使用線程池-限流操作
*/
public class SemaphoreTest2 {
//定義一個(gè)5個(gè)許可的信號(hào)量
private static Semaphore semaphore = new Semaphore(5);
//定義一個(gè)10個(gè)線程的線程池
private static ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(10,20,60,
TimeUnit.SECONDS,new LinkedBlockingQueue<>(200));
public static void main(String[] args) throws InterruptedException {
//每100ms發(fā)送一次請(qǐng)求
for(;;){
Thread.sleep(100);
threadPoolExecutor.execute(()->exec());
System.out.println("-------------------------------------");
}
}
private static void exec(){
//模擬限流場(chǎng)景
try{
semaphore.acquire(1);
//暫停2秒
Thread.sleep(2000);
System.out.println("執(zhí)行業(yè)務(wù)邏輯");
}catch (Exception e){
e.printStackTrace();
}finally {
semaphore.release(1);
}
}
}
1.2 Semaphore源碼解析
關(guān)注點(diǎn):
1.加解鎖邏輯(共享鎖)實(shí)現(xiàn)
2.競(jìng)爭鎖失敗入隊(duì)操作阻塞和喚醒同步隊(duì)列中等待線程邏輯
服了這代碼了,寫的狗屁不通
?
?
?2. countDownLatch介紹
?countDownLatch(閉鎖)是一個(gè)同步協(xié)助類,用于一個(gè)或多個(gè)線程等待,相當(dāng)于一個(gè)倒計(jì)時(shí)計(jì)數(shù)器,需要當(dāng)計(jì)數(shù)器為0時(shí)才釋放等待線程執(zhí)行,等待線程會(huì)一次性全部返回,計(jì)數(shù)器不會(huì)重置,需要重置需要使用CyclicBarrier
?常用方法:
public void await() 讓線程等待 public boolean await(long timeout, TimeUnit unit) 讓線程等待一段時(shí)間,沒有置為0執(zhí)行業(yè)務(wù) countDown() count減1
countDownLatch比join方法更加靈活,join方法底層在不停檢測(cè)線程狀態(tài)是否存活。
countDownLatch與CyclicBarrier區(qū)別:
1.countDownLatch只能使用一次,CyclicBarrier可以通過reset方法重復(fù)使用
2.countDownLatch是通過AQS的共享鎖實(shí)現(xiàn)的,CyclicBarrier是通過reentrantlock的獨(dú)占鎖和condition實(shí)現(xiàn)線程喚醒。
2.1 多個(gè)線程等待實(shí)戰(zhàn)
定義一個(gè)計(jì)數(shù)器為3的閉鎖,線程掛起,等待2秒計(jì)數(shù)器減1,直到最后一個(gè)線程減到0跑線程
import java.util.concurrent.CountDownLatch;
public class CountDownLatchTest {
//定義一個(gè)計(jì)數(shù)器為3的閉鎖
private static CountDownLatch countDownLatch = new CountDownLatch(3);
public static void main(String[] args) throws InterruptedException {
for (int i =0 ;i<5;i++){
//阻塞線程
new Thread(()->{
try{
countDownLatch.await();
System.out.println(Thread.currentThread().getName()+"執(zhí)行業(yè)務(wù)");
}catch(Exception e){
e.printStackTrace();
}
}).start();
//等待2秒計(jì)數(shù)器減1
Thread.sleep(2000);
countDownLatch.countDown();
}
}
}
?2.2 主線程等待
import java.util.concurrent.CountDownLatch;
public class CountDownLatchTest2 {
public static void main(String[] args) throws InterruptedException {
//1. 定義一個(gè)計(jì)數(shù)器為3的線程
CountDownLatch countDownLatch = new CountDownLatch(3);
//2.讓線程計(jì)數(shù)器減1
for(int i=0;i<3;i++){
new Thread(()->{
try{
Thread.sleep(1000);
countDownLatch.countDown();
}catch (Exception e){
e.printStackTrace();
}
}).start();
}
//3.主線程阻塞,當(dāng)計(jì)數(shù)器為0時(shí)執(zhí)行業(yè)務(wù)
countDownLatch.await();
System.out.println("執(zhí)行業(yè)務(wù)");
}
}
2.3 源碼分析
關(guān)注點(diǎn):
加解鎖邏輯
1. countDownLatch.await()加鎖:默認(rèn)寫死1永遠(yuǎn)waitStatus為-1走阻塞線程邏輯
2. countDownLatch.countDown()解鎖:cas操作減1,直到為0執(zhí)行喚醒線程邏輯?
解決synchronized兩個(gè)線程導(dǎo)致的死鎖問題:使用wait方法釋放鎖的形式解決,線上只能kill了
?
原文鏈接:https://blog.csdn.net/qq_21575929/article/details/124658407
相關(guān)推薦
- 2022-09-25 Clion配置STM32開發(fā)環(huán)境printf函數(shù)打印浮點(diǎn)數(shù)快速設(shè)置方法
- 2022-05-23 c++?qt自定義搜索編輯框的實(shí)現(xiàn)方法_C 語言
- 2022-06-16 Python語法學(xué)習(xí)之正則表達(dá)式的使用詳解_python
- 2022-12-10 C++?Boost?Spirit進(jìn)階教程_C 語言
- 2022-05-03 SQL?Server查詢某個(gè)字段在哪些表中存在_MsSql
- 2022-09-07 python讀取mat文件中的struct問題_python
- 2022-11-04 SQL?Server還原完整備份和差異備份的操作過程_MsSql
- 2022-10-17 .Net?Core使用Coravel實(shí)現(xiàn)任務(wù)調(diào)度的完整步驟_實(shí)用技巧
- 最近更新
-
- window11 系統(tǒng)安裝 yarn
- 超詳細(xì)win安裝深度學(xué)習(xí)環(huán)境2025年最新版(
- Linux 中運(yùn)行的top命令 怎么退出?
- MySQL 中decimal 的用法? 存儲(chǔ)小
- get 、set 、toString 方法的使
- @Resource和 @Autowired注解
- Java基礎(chǔ)操作-- 運(yùn)算符,流程控制 Flo
- 1. Int 和Integer 的區(qū)別,Jav
- spring @retryable不生效的一種
- Spring Security之認(rèn)證信息的處理
- Spring Security之認(rèn)證過濾器
- Spring Security概述快速入門
- Spring Security之配置體系
- 【SpringBoot】SpringCache
- Spring Security之基于方法配置權(quán)
- redisson分布式鎖中waittime的設(shè)
- maven:解決release錯(cuò)誤:Artif
- restTemplate使用總結(jié)
- Spring Security之安全異常處理
- MybatisPlus優(yōu)雅實(shí)現(xiàn)加密?
- Spring ioc容器與Bean的生命周期。
- 【探索SpringCloud】服務(wù)發(fā)現(xiàn)-Nac
- Spring Security之基于HttpR
- Redis 底層數(shù)據(jù)結(jié)構(gòu)-簡單動(dòng)態(tài)字符串(SD
- arthas操作spring被代理目標(biāo)對(duì)象命令
- Spring中的單例模式應(yīng)用詳解
- 聊聊消息隊(duì)列,發(fā)送消息的4種方式
- bootspring第三方資源配置管理
- GIT同步修改后的遠(yuǎn)程分支