成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

都已經2023年了,你還不知道StampedLock嗎?

開發 前端
本文主要講解了StampedLock?的功能和使用,至于原理,StampedLock雖然不像其它鎖一樣定義了內部類來實現AQS框架,但是StampedLock的基本實現思路還是利用CLH隊列進行線程的管理,通過同步狀態值來表示鎖的狀態和類型,具體的源碼實現大家感興趣的自己可以追蹤看看。

?概述

想到讀寫鎖,大家第一時間想到的可能是ReentrantReadWriteLock?。實際上,在jdk8以后,java提供了一個性能更優越的讀寫鎖并發類StampedLock?,該類的設計初衷是作為一個內部工具類,用于輔助開發其它線程安全組件,用得好,該類可以提升系統性能,用不好,容易產生死鎖和其它莫名其妙的問題。本文主要和大家一起學習下StampedLock的功能和使用。

StampedLock介紹

StampedLock?的狀態由版本和模式組成。鎖獲取方法返回一個戳,該戳表示并控制對鎖狀態的訪問。StampedLock提供了3種模式控制訪問鎖:

寫模式

獲取寫鎖,它是獨占的,當鎖處于寫模式時,無法獲得讀鎖,所有樂觀讀驗證都將失敗。

  • writeLock(): 阻塞等待獨占獲取鎖,返回一個戳, 如果是0表示獲取失敗。
  • tryWriteLock():嘗試獲取一個寫鎖,返回一個戳, 如果是0表示獲取失敗。
  • long tryWriteLock(long time, TimeUnit unit): 嘗試獲取一個獨占寫鎖,可以等待一段事件,返回一個戳, 如果是0表示獲取失敗。
  • long writeLockInterruptibly(): 試獲取一個獨占寫鎖,可以被中斷,返回一個戳, 如果是0表示獲取失敗。
  • unlockWrite(long stamp):釋放獨占寫鎖,傳入之前獲取的戳。
  • tryUnlockWrite():如果持有寫鎖,則釋放該鎖,而不需要戳值。這種方法可能對錯誤后的恢復很有用。
long stamp = lock.writeLock();
try {
....
} finally {
lock.unlockWrite(stamp);
}

讀模式

悲觀的方式后去非獨占讀鎖。

  • readLock(): 阻塞等待獲取非獨占的讀鎖,返回一個戳, 如果是0表示獲取失敗。
  • tryReadLock():嘗試獲取一個讀鎖,返回一個戳, 如果是0表示獲取失敗。
  • long tryReadLock(long time, TimeUnit unit): 嘗試獲取一個讀鎖,可以等待一段事件,返回一個戳, 如果是0表示獲取失敗。
  • long readLockInterruptibly(): 阻塞等待獲取非獨占的讀鎖,可以被中斷,返回一個戳, 如果是0表示獲取失敗。
  • unlockRead(long stamp):釋放非獨占的讀鎖,傳入之前獲取的戳。
  • tryUnlockRead():如果讀鎖被持有,則釋放一次持有,而不需要戳值。這種方法可能對錯誤后的恢復很有用。
long stamp = lock.readLock();
try {
....
} finally {
lock.unlockRead(stamp);
}

樂觀讀模式

樂觀讀也就是若讀的操作很多,寫的操作很少的情況下,你可以樂觀地認為,寫入與讀取同時發生幾率很少,因此不悲觀地使用完全的讀取鎖定,程序可以查看讀取資料之后,是否遭到寫入執行的變更,再采取后續的措施(重新讀取變更信息,或者拋出異常) ,這一個小小改進,可大幅度提高程序的吞吐量。

StampedLock?支持 tryOptimisticRead()方法,讀取完畢后做一次戳校驗,如果校驗通過,表示這期間沒有其他線程的寫操作,數據可以安全使用,如果校驗沒通過,需要重新獲取讀鎖,保證數據一致性。

  • tryOptimisticRead(): 返回稍后可以驗證的戳記,如果獨占鎖定則返回零。
  • boolean validate(long stamp): 如果自給定戳記發行以來鎖還沒有被獨占獲取,則返回true。
long stamp = lock.tryOptimisticRead();
// 驗戳
if(!lock.validate(stamp)){
// 鎖升級
}

此外,StampedLock 提供了api實現上面3種方式進行轉換:

  • long tryConvertToWriteLock(long stamp)

如果鎖狀態與給定的戳記匹配,則執行以下操作之一。如果戳記表示持有寫鎖,則返回它。或者,如果是讀鎖,如果寫鎖可用,則釋放讀鎖并返回寫戳記。或者,如果是樂觀讀,則僅在立即可用時返回寫戳記。該方法在所有其他情況下返回零

  • long tryConvertToReadLock(long stamp)

如果鎖狀態與給定的戳記匹配,則執行以下操作之一。如果戳記表示持有寫鎖,則釋放它并獲得讀鎖。或者,如果是讀鎖,返回它。或者,如果是樂觀讀,則僅在立即可用時才獲得讀鎖并返回讀戳記。該方法在所有其他情況下返回零。

  • long tryConvertToOptimisticRead(long stamp)

如果鎖狀態與給定的戳記匹配,那么如果戳記表示持有鎖,則釋放它并返回一個觀察戳記。或者,如果是樂觀讀,則在驗證后返回它。該方法在所有其他情況下返回0,因此作為“tryUnlock”的形式可能很有用。

演示例子

下面用一個例子演示下StampedLock的使用,例子來源jdk中的javadoc。

@Slf4j
@Data
public class Point {
private double x, y;
private final StampedLock sl = new StampedLock();

void move(double deltaX, double throws{
//涉及對共享資源的修改,使用寫鎖-獨占操作
long stamp = sl.writeLock();
log.info("writeLock lock success");
Thread.sleep(500);
try {
x += deltaX;
y += deltaY;
} finally {
sl.unlockWrite(stamp);
log.info("unlock write lock success");
}
}

/**
* 使用樂觀讀鎖訪問共享資源
* 注意:樂觀讀鎖在保證數據一致性上需要拷貝一份要操作的變量到方法棧,并且在操作數據時候可能其他寫線程已經修改了數據,
* 而我們操作的是方法棧里面的數據,也就是一個快照,所以最多返回的不是最新的數據,但是一致性還是得到保障的。
*
* @return
*/
double distanceFromOrigin() throws{
long stamp = sl.tryOptimisticRead(); // 使用樂觀讀鎖
log.info("tryOptimisticRead lock success");
// 睡一秒中
Thread.sleep(1000);
double currentX = x, currentY = y; // 拷貝共享資源到本地方法棧中
if (!sl.validate(stamp)) { // 如果有寫鎖被占用,可能造成數據不一致,所以要切換到普通讀鎖模式
log.info("validate stamp error");
stamp = sl.readLock();
log.info("readLock success");
try {
currentX = x;
currentY = y;
} finally {
sl.unlockRead(stamp);
log.info("unlock read success");
}
}
return Math.sqrt(currentX * currentX + currentY * currentY);
}

void moveIfAtOrigin(double newX, double{ // upgrade
// Could instead start with optimistic, not read mode
long stamp = sl.readLock();
try {
while (x == 0.0 && y == 0.0) {
long ws = sl.tryConvertToWriteLock(stamp); //讀鎖轉換為寫鎖
if (ws != 0L) {
stamp = ws;
x = newX;
y = newY;
break;
} else {
sl.unlockRead(stamp);
stamp = sl.writeLock();
}
}
} finally {
sl.unlock(stamp);
}
}
}

測試用例:

@Test
public void testStamped() throws InterruptedException {
Point point = new Point();
point.setX(1);
point.setY(2);
// 線程0 執行了樂觀讀
Thread thread0 = new Thread(() -> {
try {
// 樂觀讀
point.distanceFromOrigin();
} catch (InterruptedException e) {
e.printStackTrace();
}
}, "thread-0");
thread0.start();

Thread.sleep(500);
// 線程1 執行寫鎖
Thread thread1 = new Thread(() -> {
// 樂觀讀
try {
point.move(3, 4);
} catch (InterruptedException e) {
e.printStackTrace();
}
}, "thread-1");
thread1.start();

thread0.join();
thread1.join();
}

結果:

圖片

性能對比

正是由于StampedLock?的樂觀讀模式,早就StampedLock的高性能和高吞吐量,那么具體的性能提高有多少呢?

下圖是和ReadWritLock相比,在一個線程情況下,讀速度是其4倍左右,寫是1倍。

圖片

下圖是16個線程情況下,讀性能是其幾十倍,寫性能也是近10倍左右:

圖片

下圖是吞吐量提高:

圖片

那么這樣是不是說StampedLock?可以全方位的替代ReentrantReadWriteLock?, 答案是否定的,StampedLock?相對于ReentrantReadWriteLock有下面兩個問題:

  • 不支持條件變量Condition
  • 不支持可重入

所以最終選擇StampedLock?還是ReentrantReadWriteLock,還是要看具體的業務場景。

總結

本文主要講解了StampedLock?的功能和使用,至于原理,StampedLock雖然不像其它鎖一樣定義了內部類來實現AQS框架,但是StampedLock的基本實現思路還是利用CLH隊列進行線程的管理,通過同步狀態值來表示鎖的狀態和類型,具體的源碼實現大家感興趣的自己可以追蹤看看。

責任編輯:武曉燕 來源: JAVA旭陽
相關推薦

2019-12-24 09:49:02

微軟英語瀏覽器

2016-07-22 17:55:07

云計算

2022-09-19 18:32:22

函數編程語言

2024-03-07 07:58:26

Web開發響應媒體查詢工具

2022-05-05 12:02:45

SCSS函數開發

2020-12-14 07:51:16

JS 技巧虛值

2018-09-02 15:43:56

Python代碼編程語言

2022-07-17 06:53:24

微服務架構

2024-01-26 06:26:42

Linuxfzf工具

2021-10-22 09:41:26

橋接模式設計

2018-07-10 11:33:58

計算器iPhone刪除

2020-06-12 09:20:33

前端Blob字符串

2020-07-28 08:26:34

WebSocket瀏覽器

2020-10-28 08:06:09

Vue3框架數據

2015-07-13 08:49:54

2021-03-18 14:02:56

iOS蘋果細節

2019-10-28 08:44:29

Code Review代碼團隊

2021-04-15 12:30:18

ServletSpringMVC 版本

2022-10-12 08:22:44

Guava工具Collection

2022-05-20 08:02:07

Mono-repoGit策略
點贊
收藏

51CTO技術棧公眾號

主站蜘蛛池模板: 精品久久久久久久久久久久 | 日韩在线视频一区 | 国产精品1区2区 | 福利片在线 | 精精国产xxxx视频在线播放 | 欧美性吧| 日韩欧美国产精品 | 国产一级片精品 | 亚欧性视频| 一区二区在线 | 欧美综合视频在线 | 亚洲欧美中文日韩在线v日本 | 精品国产一区二区三区免费 | 91视频正在播放 | 秋霞精品| 日韩免费一区 | av网站免费| 国产女人与拘做受免费视频 | 国产精品久久久久久久久久三级 | 亚洲高清在线观看 | 亚洲一区二区三区在线视频 | 一区二区免费在线观看 | 欧美一区在线看 | 国产精品一级 | 国产欧美一区二区三区另类精品 | 97视频久久 | 欧美精品一区在线 | 视频二区在线观看 | 亚洲国产精品成人 | 亚洲视频在线观看免费 | 在线看无码的免费网站 | 国产色爽| 久久久五月天 | 国产精品一区久久久 | 一级毛片色一级 | 91精品国产91久久久久久不卞 | 中文字幕日韩欧美一区二区三区 | 九久久 | 秋霞在线一区二区 | 91网站在线看 | 精品国产色 |