什么是樂觀鎖和悲觀鎖
悲觀鎖,顧名思義,就是很悲觀,每次去拿數據的時候都認為別人會修改,所以每次在拿數據的時候都會上鎖,這樣別人想拿這個數據就會block直到它拿到鎖。悲觀鎖適用於並發競爭很厲害,寫比較多的操作。
樂觀鎖,就是很樂觀,每次去拿數據的時候都認為別人不會修改,所以不會上鎖,但是在提交更新的時候會判斷一下在此期間別人有沒有去更新這個數據。
樂觀鎖適用於讀多寫少的應用場景,這樣可以提高吞吐量。
悲觀鎖的實現
數據庫排它鎖、行鎖、表鎖、讀鎖、寫鎖、共享鎖。
排它鎖(下面這個例子只給一條數據加了鎖,也叫行鎖):當一個事物加入排他鎖后,不允許其他事務加共享鎖或者排它鎖讀取,更加不允許其他事務修改加鎖的行。
select * from account where name=”xxx” for update
共享鎖:允許不同事務之前共享加鎖讀取,但不允許其它事務修改或者加入排他鎖。如果有修改必須等待一個事務提交完成,才可以執行,容易出現死鎖。
- 允許其它事務也增加共享鎖讀取
- 不允許其它事物增加排他鎖(
for update
) - 當事務同時增加共享鎖時候,事務的更新必須等待先執行的事務commit后才行,如果同時並發太大可能很容易造成死鎖
select * from account where name=”xxx” lock in share mode
Java中Synchronized和ReentrantLock
樂觀鎖的實現
數據庫的版本號機制(或者時間戳)
update account set price=100,version=2 where version=1
Java中的CAS(compare and swap)算法實現。CAS算法涉及到三個操作數:
- 需要讀寫的內存值 V
- 進行比較的值 A
- 擬寫入的新值 B
當且僅當 V 的值等於 A時,CAS通過原子方式用新值B來更新V的值,否則不會執行任何操作(比較和替換是一個原子操作)。一般情況下是一個自旋操作,即不斷的重試。CAS需要考慮數據變化“ABA”的問題,這時可以檢測是否被改過。(參見java.util.concurrent.atomic.AtomicStampedReference )