前方一系列大事務問題來襲,請及時拉響警報
阿新 • • 發佈:2021-01-02
該類自 JDK 8 加入,是為了進一步優化讀效能,它的特點是在使用讀鎖、寫鎖時都必須配合【戳】使用
讀鎖:
long stamp = lock.readLock();
lock.unlockRead(stamp);
寫鎖:
long stamp = lock.writeLock();
lock.unlockWrite(stamp);
StampedLock 支援tryOptimisticRead() 方法(樂觀讀),讀取完畢後需要做一次 戳校驗 如果校驗通過,表示這期間確實沒有寫操作,資料可以安全使用,如果校驗沒通過,需要重新獲取讀鎖,保證資料安全。
long stamp = lock.tryOptimisticRead();
// 驗戳
if(!lock.validate(stamp)){
// 鎖升級
}
測試程式碼:
import lombok.extern.slf4j.Slf4j; import java.util.concurrent.locks.StampedLock; import static com.dalianpai.Sleeper.sleep; /** * @author WGR * @create 2020/12/31 -- 13:55 */ @Slf4j(topic = "c.TestStampedLock") public class TestStampedLock { public static void main(String[] args) { DataContainerStamped dataContainer = new DataContainerStamped(1); new Thread(() -> { dataContainer.read(1); }, "t1").start(); sleep(0.5); new Thread(() -> { dataContainer.read(0); }, "t2").start(); } } @Slf4j(topic = "c.DataContainerStamped") class DataContainerStamped { private int data; private final StampedLock lock = new StampedLock(); public DataContainerStamped(int data) { this.data = data; } public int read(int readTime) { long stamp = lock.tryOptimisticRead(); log.debug("optimistic read locking...{}", stamp); sleep(readTime); if (lock.validate(stamp)) { log.debug("read finish...{}, data:{}", stamp, data); return data; } // 鎖升級 - 讀鎖 log.debug("updating to read lock... {}", stamp); try { stamp = lock.readLock(); log.debug("read lock {}", stamp); sleep(readTime); log.debug("read finish...{}, data:{}", stamp, data); return data; } finally { log.debug("read unlock {}", stamp); lock.unlockRead(stamp); } } public void write(int newData) { long stamp = lock.writeLock(); log.debug("write lock {}", stamp); try { sleep(2); this.data = newData; } finally { log.debug("write unlock {}", stamp); lock.unlockWrite(stamp); } } }
測試 讀-讀
可以優化
public static void main(String[] args) { DataContainerStamped dataContainer = new DataContainerStamped(1); new Thread(() -> { dataContainer.read(10); }, "t1").start(); sleep(0.5); new Thread(() -> { dataContainer.read(0); }, "t2").start(); } }
測試描述:當t1執行緒先搶到樂觀讀鎖,然後睡眠10秒,t2晚t1 0.5秒搶到鎖,然後直接結束,並沒有堵塞住。
測試讀-寫
時優化讀補加讀鎖
public static void main(String[] args) {
DataContainerStamped dataContainer = new DataContainerStamped(1);
new Thread(() -> {
dataContainer.read(1);
}, "t1").start();
sleep(0.5);
new Thread(() -> {
dataContainer.write(100);
}, "t2").start();
}
測試描述:當t1執行緒先搶到樂觀讀鎖,然後休眠1秒鐘,t2執行緒晚t1執行緒0.5秒搶到讀鎖,然後休眠2秒,這個時候t1執行緒醒來,驗籤失敗,這個時候就會鎖進升級成讀鎖,但是鎖還在寫鎖那邊,只能等寫鎖釋放,讀鎖才能拿到。
注意:
StampedLock不支援條件變數
StampedLock不支援可重入