網站首頁 編程語言 正文
目錄
1.Semaphore介紹
1.1 限流操作實戰
1.2 Semaphore源碼解析
?2. countDownLatch介紹
2.1 多個線程等待實戰
?2.2 主線程等待
2.3 源碼分析
1.Semaphore介紹
semaphorer(信號量),是一個基于AQS框架實現的工具類,也是操作系統PV操作在java中的實現。通過發放許可來控制線程,只有拿到許可的線程才能執行代碼,常用于限流操作。
PV操作是一種操作系統實現進程互斥與同步的有效方法:P表示通過,V表示釋放。
P操作:S-1=X,如果X>=0線程執行,如果小于0放入等待隊列中。
V操作:S+1=X,如果X>=0線程執行,如果小于0從等待隊列釋放一個等待線程。
構造器(默認非公平鎖,也有公平鎖實現):
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 限流操作實戰
模擬限流操作
1. 5個線程發送3個許可。
2. 10個核心線程發送5個許可。
import java.util.concurrent.Semaphore;
/**
* 限流操作
*/
public class SemaphoreTest {
private static Semaphore semaphore = new Semaphore(3);//發放三個許可
public static void main(String[] args) throws Exception {
//執行5個線程
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 {
//定義一個5個許可的信號量
private static Semaphore semaphore = new Semaphore(5);
//定義一個10個線程的線程池
private static ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(10,20,60,
TimeUnit.SECONDS,new LinkedBlockingQueue<>(200));
public static void main(String[] args) throws InterruptedException {
//每100ms發送一次請求
for(;;){
Thread.sleep(100);
threadPoolExecutor.execute(()->exec());
System.out.println("-------------------------------------");
}
}
private static void exec(){
//模擬限流場景
try{
semaphore.acquire(1);
//暫停2秒
Thread.sleep(2000);
System.out.println("執行業務邏輯");
}catch (Exception e){
e.printStackTrace();
}finally {
semaphore.release(1);
}
}
}
1.2 Semaphore源碼解析
關注點:
1.加解鎖邏輯(共享鎖)實現
2.競爭鎖失敗入隊操作阻塞和喚醒同步隊列中等待線程邏輯
服了這代碼了,寫的狗屁不通
?
?
?2. countDownLatch介紹
?countDownLatch(閉鎖)是一個同步協助類,用于一個或多個線程等待,相當于一個倒計時計數器,需要當計數器為0時才釋放等待線程執行,等待線程會一次性全部返回,計數器不會重置,需要重置需要使用CyclicBarrier
?常用方法:
public void await() 讓線程等待 public boolean await(long timeout, TimeUnit unit) 讓線程等待一段時間,沒有置為0執行業務 countDown() count減1
countDownLatch比join方法更加靈活,join方法底層在不停檢測線程狀態是否存活。
countDownLatch與CyclicBarrier區別:
1.countDownLatch只能使用一次,CyclicBarrier可以通過reset方法重復使用
2.countDownLatch是通過AQS的共享鎖實現的,CyclicBarrier是通過reentrantlock的獨占鎖和condition實現線程喚醒。
2.1 多個線程等待實戰
定義一個計數器為3的閉鎖,線程掛起,等待2秒計數器減1,直到最后一個線程減到0跑線程
import java.util.concurrent.CountDownLatch;
public class CountDownLatchTest {
//定義一個計數器為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()+"執行業務");
}catch(Exception e){
e.printStackTrace();
}
}).start();
//等待2秒計數器減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. 定義一個計數器為3的線程
CountDownLatch countDownLatch = new CountDownLatch(3);
//2.讓線程計數器減1
for(int i=0;i<3;i++){
new Thread(()->{
try{
Thread.sleep(1000);
countDownLatch.countDown();
}catch (Exception e){
e.printStackTrace();
}
}).start();
}
//3.主線程阻塞,當計數器為0時執行業務
countDownLatch.await();
System.out.println("執行業務");
}
}
2.3 源碼分析
關注點:
加解鎖邏輯
1. countDownLatch.await()加鎖:默認寫死1永遠waitStatus為-1走阻塞線程邏輯
2. countDownLatch.countDown()解鎖:cas操作減1,直到為0執行喚醒線程邏輯?
解決synchronized兩個線程導致的死鎖問題:使用wait方法釋放鎖的形式解決,線上只能kill了
?
原文鏈接:https://blog.csdn.net/qq_21575929/article/details/124658407
相關推薦
- 2022-08-28 c++在windows、linux下獲取指定文件夾下所有文件名的方法
- 2023-11-13 linux平臺下ZeroMQ zmq(C++)編譯安裝以及調用
- 2022-11-04 asp.net?core?認證和授權實例詳解_實用技巧
- 2022-11-15 Flutter異步操作實現流程詳解_Android
- 2022-12-22 淺析Go語言中數組的這些細節_Golang
- 2022-09-28 C語言關于二叉樹中堆的創建和使用整理_C 語言
- 2022-11-09 Android實現圖片上傳蒙層進度條_Android
- 2023-01-02 Flutter組件生命周期和App生命周期示例解析_Android
- 最近更新
-
- window11 系統安裝 yarn
- 超詳細win安裝深度學習環境2025年最新版(
- Linux 中運行的top命令 怎么退出?
- MySQL 中decimal 的用法? 存儲小
- get 、set 、toString 方法的使
- @Resource和 @Autowired注解
- Java基礎操作-- 運算符,流程控制 Flo
- 1. Int 和Integer 的區別,Jav
- spring @retryable不生效的一種
- Spring Security之認證信息的處理
- Spring Security之認證過濾器
- Spring Security概述快速入門
- Spring Security之配置體系
- 【SpringBoot】SpringCache
- Spring Security之基于方法配置權
- redisson分布式鎖中waittime的設
- maven:解決release錯誤:Artif
- restTemplate使用總結
- Spring Security之安全異常處理
- MybatisPlus優雅實現加密?
- Spring ioc容器與Bean的生命周期。
- 【探索SpringCloud】服務發現-Nac
- Spring Security之基于HttpR
- Redis 底層數據結構-簡單動態字符串(SD
- arthas操作spring被代理目標對象命令
- Spring中的單例模式應用詳解
- 聊聊消息隊列,發送消息的4種方式
- bootspring第三方資源配置管理
- GIT同步修改后的遠程分支