Java线程安全StampedLock
轉載請標明出處:http://blog.csdn.net/zhaoyanjun6/article/details/120854573
本文出自【趙彥軍的博客】
Java線程安全StampedLock
Java線程安全Lock、ReentrantLock、ReentrantReadWriteLock
Java線程安全集合總結
Java原子操作Atomic
文章目錄
- ReadWriteLock
- 小結
ReadWriteLock
前面介紹的ReadWriteLock可以解決多線程同時讀,但只有一個線程能寫的問題。
如果我們深入分析ReadWriteLock,會發(fā)現(xiàn)它有個潛在的問題:如果有線程正在讀,寫線程需要等待讀線程釋放鎖后才能獲取寫鎖,即讀的過程中不允許寫,這是一種悲觀的讀鎖。
要進一步提升并發(fā)執(zhí)行效率,Java 8引入了新的讀寫鎖:StampedLock。
StampedLock和ReadWriteLock相比,改進之處在于:讀的過程中也允許獲取寫鎖后寫入!這樣一來,我們讀的數(shù)據(jù)就可能不一致,所以,需要一點額外的代碼來判斷讀的過程中是否有寫入,這種讀鎖是一種樂觀鎖。
樂觀鎖的意思就是樂觀地估計讀的過程中大概率不會有寫入,因此被稱為樂觀鎖。反過來,悲觀鎖則是讀的過程中拒絕有寫入,也就是寫入必須等待。顯然樂觀鎖的并發(fā)效率更高,但一旦有小概率的寫入導致讀取的數(shù)據(jù)不一致,需要能檢測出來,再讀一遍就行。
我們來看例子:
public class Point {private final StampedLock stampedLock = new StampedLock();private double x;private double y;public void move(double deltaX, double deltaY) {long stamp = stampedLock.writeLock(); // 獲取寫鎖try {x += deltaX;y += deltaY;} finally {stampedLock.unlockWrite(stamp); // 釋放寫鎖}}public double distanceFromOrigin() {long stamp = stampedLock.tryOptimisticRead(); // 獲得一個樂觀讀鎖// 注意下面兩行代碼不是原子操作// 假設x,y = (100,200)double currentX = x;// 此處已讀取到x=100,但x,y可能被寫線程修改為(300,400)double currentY = y;// 此處已讀取到y(tǒng),如果沒有寫入,讀取是正確的(100,200)// 如果有寫入,讀取是錯誤的(100,400)if (!stampedLock.validate(stamp)) { // 檢查樂觀讀鎖后是否有其他寫鎖發(fā)生stamp = stampedLock.readLock(); // 獲取一個悲觀讀鎖try {currentX = x;currentY = y;} finally {stampedLock.unlockRead(stamp); // 釋放悲觀讀鎖}}return Math.sqrt(currentX * currentX + currentY * currentY);} }和ReadWriteLock相比,寫入的加鎖是完全一樣的,不同的是讀取。注意到首先我們通過tryOptimisticRead()獲取一個樂觀讀鎖,并返回版本號。接著進行讀取,讀取完成后,我們通過validate()去驗證版本號,如果在讀取過程中沒有寫入,版本號不變,驗證成功,我們就可以放心地繼續(xù)后續(xù)操作。如果在讀取過程中有寫入,版本號會發(fā)生變化,驗證將失敗。在失敗的時候,我們再通過獲取悲觀讀鎖再次讀取。由于寫入的概率不高,程序在絕大部分情況下可以通過樂觀讀鎖獲取數(shù)據(jù),極少數(shù)情況下使用悲觀讀鎖獲取數(shù)據(jù)。
可見,StampedLock把讀鎖細分為樂觀讀和悲觀讀,能進一步提升并發(fā)效率。但這也是有代價的:一是代碼更加復雜,二是StampedLock是不可重入鎖,不能在一個線程中反復獲取同一個鎖。
StampedLock還提供了更復雜的將悲觀讀鎖升級為寫鎖的功能,它主要使用在if-then-update的場景:即先讀,如果讀的數(shù)據(jù)滿足條件,就返回,如果讀的數(shù)據(jù)不滿足條件,再嘗試寫。
小結
StampedLock提供了樂觀讀鎖,可取代ReadWriteLock以進一步提升并發(fā)性能;
StampedLock是不可重入鎖。
總結
以上是生活随笔為你收集整理的Java线程安全StampedLock的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Java阻塞队列 LinkedBlock
- 下一篇: Java原子操作Atomic