
[TOC]
## 一、讀寫鎖
在我的[《java并發編程》](https://mp.weixin.qq.com/mp/appmsgalbum?__biz=MzU0NDU5MTk1MQ==&action=getalbum&album_id=1576334194996232194#wechat_redirect)上一篇文章中為大家介紹了《ReentrantLock讀寫鎖》,**ReentrantReadWriteLock可以保證最多同時有一個線程在寫數據,或者可以同時有多個線程讀數據,但讀寫不能同時進行。**
比如你正在做的是日志,有一個線程正在做寫操作,但是在寫日志的時候你可能需要把日志集中轉移到集中管理日志服務,但是此時讀線程不能讀數據(因為無法獲取讀鎖)。面對這個需求,ReentrantReadWriteLock顯然不是我們的解決方案,我們希望:**最多一個線程在進行寫操作(加寫鎖),但是同時允許多個線程進行讀操作(加讀鎖),解決方案是StampedLock。**
## 二、悲觀讀鎖
StampedLock 同樣可以實現寫鎖和讀鎖的功能,Stamped在英文中有印章的含義,對于StampedLock大家可以這么理解,使用一個印章加鎖,必須使用該印章解鎖。
~~~
public class TestStampedLock {
Map<String,String> map = new HashMap<>();
//鎖對象
private StampedLock lock = new StampedLock();
//寫操作函數
public void put(String key, String value){
long stamp = lock.writeLock(); //加寫鎖
try {
map.put(key, value); //寫操作
} finally {
lock.unlockWrite(stamp); //釋放寫鎖
}
}
public String get(String key) {
long stamp = lock.readLock(); //加讀鎖
try {
return map.get(key); //讀操作
} finally {
lock.unlockRead(stamp); //釋放讀鎖
}
}
}
~~~
上文中的讀鎖readLock,在StampedLock模式中被稱為**悲觀讀鎖**,之所以叫做悲觀讀鎖是和StampedLock支持的另一種模式“**樂觀讀**”相對應的。
寫鎖、悲觀讀鎖的語義和 ReadWriteLock 的寫鎖、讀鎖的語義基本是一致的,**允許多個線程同時獲取悲觀讀鎖,但是只允許一個線程獲取寫鎖,寫鎖和悲觀讀鎖是互斥的。多線程環境下,寫操作的同時不能讀**。所以到這里為止,StampedLock與ReadWriteLock并沒有很大的區別。
## 三、樂觀讀
需要注意的是,這里我寫的是**樂觀讀**,而不是樂觀讀鎖,因為樂觀讀是不加鎖的。通過tryOptimisticRead()函數獲取一個stamp,這里的tryOptimisticRead() 就是樂觀讀,樂觀讀因為沒有加鎖,所以讀取數據的性能會更高一點。即:已經有寫操作線程加鎖的同時,仍然允許讀操作線程繼續進行。
如果你的讀寫操作有比較強的時間點數據一致性要求,即:同一個時間點讀操作讀到的數據,一定與該時間點寫操作保持數據一致性。那么,你就需要進行validate校驗,stamp此時可以理解為一個版本號,如果寫操作版本為2,讀操作版本為1,說明你讀到的數據不是最新的。你需要去讀取最新版本的數據(版本號為2),所以需要升級為悲觀讀鎖,代碼如下:
~~~
public String readWithOptimisticLock(String key) {
long stamp = lock.tryOptimisticRead(); //樂觀讀
String value = map.get(key); //讀取數據
if(!lock.validate(stamp)) { //校驗數據是否是最新版本
stamp = lock.readLock(); //如果不是,升級為悲觀讀鎖
try {
return map.get(key);
} finally {
lock.unlock(stamp);
}
}
return value;
}
~~~
- 線程
- 1.進程和線程-鎖與信號量
- 2.Thread類線程狀態轉換
- 2.并發與并行-同步與異步
- 4.線程池
- 5.對象級別與類級別的同步鎖
- 6.創建線程的四種方式
- 7.臨界區-阻塞-活鎖-死鎖
- 2.JMM多線程模型
- JUC
- BlockingQueue
- ArrayBlockingQueue
- DelayQueue
- LinkedBlockingQueue
- PriorityBlockingQueue
- SynchronousQueue
- BlockingDeque
- ConcurrentHashMap
- CountDownLatch
- CyclicBarrier
- Exchanger
- AtomicInteger
- Lock
- Condition
- ReentrantLock讀寫鎖
- StampedLock
- Semaphore