在讀多寫少的場景中,StampedLock比ReadWriteLock性能要好。
Why?
StampedLock 支持的三種鎖模式
ReadWriteLock 支持兩種模式:一種是讀鎖,一種是寫鎖。而 StampedLock 支持三種模 式,分別是:寫鎖、悲觀讀鎖和樂觀讀。StampedLock 的性能之所以比 ReadWriteLock 還要好,其關(guān)鍵是 StampedLock 支持樂觀讀的方式。ReadWriteLock 支持多個線程同時讀,但是當多個線程同時讀的時候,所有的寫操作會被阻塞;而 StampedLock 提供的樂觀讀,是允許一個線程獲取寫鎖的,也就是說不是所有的寫操作都被阻塞。
注意這里,我們用的是“樂觀讀”這個詞,而不是“樂觀讀鎖”,是要提醒你,樂觀讀這個操作是無鎖的,所以相比較 ReadWriteLock 的讀鎖,樂觀讀的性能更好一些。
How?
class Point {
private int x, y;
final StampedLock sl =
new StampedLock();
// 計算到原點的距離
int distanceFromOrigin() {
// 樂觀讀
long stamp =
sl.tryOptimisticRead();
// 讀入局部變量,
// 讀的過程數(shù)據(jù)可能被修改
int curX = x, curY = y;
// 判斷執(zhí)行讀操作期間,
// 是否存在寫操作,如果存在,
// 則 sl.validate 返回 false
if (!sl.validate(stamp)){
// 升級為悲觀讀鎖
stamp = sl.readLock();
try {
curX = x;
curY = y;
} finally {
// 釋放悲觀讀鎖
sl.unlockRead(stamp);
}
}
//使用方法局部變量執(zhí)行業(yè)務(wù)邏輯
return Math.sqrt(
curX * curX + curY * curY);
}
}
StampedLock 使用注意事項
對于讀多寫少的場景 StampedLock 性能很好,簡單的應(yīng)用場景基本上可以替代 ReadWriteLock,但是StampedLock 的功能僅僅是 ReadWriteLock 的子集,在使用的 時候,還是有幾個地方需要注意一下。
1 StampedLock 不支持重入。
2 StampedLock 的悲觀讀鎖、寫鎖都不支持條件變量。
3 使用 StampedLock 一定不要調(diào)用中斷操作,如果需要支持中斷功能,一定使用可 中斷的悲觀讀鎖 readLockInterruptibly() 和寫鎖 writeLockInterruptibly()。
鎖的升級和降級
StampedLock 支持鎖的降級(通過 tryConvertToReadLock() 方法實現(xiàn))和升級(通過 tryConvertToWriteLock() 方法實現(xiàn)),但使用時要慎重。
下面的代碼也源自 Java 的官方示例
private double x, y;
final StampedLock sl = new StampedLock();
void moveIfAtOrigin(double newX, double newY){
long stamp = sl.readLock();
try {
while(x == 0.0 && y == 0.0){
long ws = sl.tryConvertToWriteLock(stamp);
if (ws != 0L) {
x = newX;
y = newY;
//如果升級鎖成功,tryConvertToWriteLock(stamp)這個方法內(nèi)部會釋放悲觀讀鎖stamp。但是寫鎖需要主動釋放。
stamp = ws;
break;
} else {
sl.unlockRead(stamp);
stamp = sl.writeLock();
}
}
} finally {
sl.unlock(stamp);
}