樂觀鎖顧名思義就是在操做時很樂觀,認爲操做不會產生併發問題(不會有其餘線程對數據進行修改),所以不會上鎖。可是在更新時會判斷其餘線程在這以前有沒有對數據進行修改,通常會使用版本號機制
或CAS(compare and swap)算法
實現。
簡單理解:這裏的數據,別想太多,你儘管用,出問題了算我慫,即操做失敗後事務回滾、提示。html
version
version
set version = newVersion where version = oldVersion
version
不對,就更新失敗核心SQL:java
update table set name = 'Aron', version = version + 1 where id = #{id} and version = #{version};
原文查看請點擊 Mybatis-plus 樂觀鎖實現算法
樂觀鎖的另外一種技術技術,當多個線程嘗試使用CAS同時更新同一個變量時,只有其中一個線程能更新變量的值,而其它線程都失敗,失敗的線程並不會被掛起,而是被告知此次競爭中失敗,並能夠再次嘗試。併發
CAS
操做中包含三個操做數 :異步
V
A
B
若是內存位置V
的值與預期原值A
相匹配,那麼處理器會自動將該位置值更新爲新值B
。不然處理器不作任何操做。不管哪一種狀況,它都會在 CAS
指令以前返回該位置的值(在 CAS
的一些特殊狀況下將僅返回 CAS
是否成功,而不提取當前值)。CAS
有效地說明了「 我認爲位置 V
應該包含值 A
;若是包含該值,則將 B
放到這個位置;不然,不要更改該位置,只告訴我這個位置如今的值便可。 」這其實和樂觀鎖的衝突檢查+數據更新的原理是同樣的。ide
因爲java
的CAS
同時具備 volatile
讀和volatile
寫的內存語義,所以Java
線程之間的通訊如今有了下面四種方式:ui
A
線程寫volatile
變量,隨後B
線程讀這個volatile
變量。A
線程寫volatile
變量,隨後B
線程用CAS
更新這個volatile
變量。A
線程用CAS
更新一個volatile
變量,隨後B
線程用CAS
更新這個volatile
變量。A
線程用CAS
更新一個volatile
變量,隨後B
線程讀這個volatile
變量。Java
的CAS
會使用現代處理器上提供的高效機器級別原子指令,這些原子指令以原子方式對內存執行讀-改-寫操做,這是在多處理器中實現同步的關鍵(從本質上來講,可以支持原子性讀-改-寫指令的計算機器,是順序計算圖靈機的異步等價機器,所以任何現代的多處理器都會去支持某種能對內存執行原子性讀-改-寫操做的原子指令)。同時,volatile
變量的讀/寫和CAS
能夠實現線程之間的通訊。把這些特性整合在一塊兒,就造成了整個concurrent
包得以實現的基石。線程
仔細分析concurrent
包的源代碼實現,會發現一個通用化的實現模式:code
volatile
; volatile
的讀/寫和CAS
所具備的volatile
讀和寫的內存語義來實現線程ABA
問題好比說一個線程T1
從內存位置V
中取出A
,這時候另外一個線程T2
也從內存中取出A
,而且T2
進行了一些操做變成了B
,而後T2
又將V
位置的數據變成A
,這時候線程T1
進行CAS
操做發現內存中仍然是A
,而後T1
操做成功。儘管線程T1
的CAS
操做成功,但可能存在潛藏的問題。htm
自旋CAS
(不成功,就一直循環執行,直到成功)若是長時間不成功,會給CPU帶來很是大的執行開銷。若是JVM
能支持處理器提供的pause
指令那麼效率會有必定的提高,pause
指令有兩個做用,第一它能夠延遲流水線執行指令(de-pipeline
),使CPU
不會消耗過多的執行資源,延遲的時間取決於具體實現的版本,在一些處理器上延遲時間是零。第二它能夠避免在退出循環的時候因內存順序衝突(memory order violation
)而引發CPU流水線被清空(CPU pipeline flush
),從而提升CPU
的執行效率。
當對一個共享變量執行操做時,咱們可使用循環CAS的方式來保證原子操做,可是對多個共享變量操做時,循環CAS就沒法保證操做的原子性,這個時候就能夠用鎖,或者有一個取巧的辦法,就是把多個共享變量合併成一個共享變量來操做。好比有兩個共享變量i = 2,j = a
,合併一下ij = 2a
,而後用CAS
來操做ij。從Java 1.5
開始JDK提供了AtomicReference
類來保證引用對象之間的原子性,你能夠把多個變量放在一個對象裏來進行CAS
操做。
老是假設最壞的狀況,每次取數據時都認爲其餘線程會修改,因此都會加(悲觀)鎖。一旦加鎖,不一樣線程同時執行時,只能有一個線程執行,其餘的線程在入口處等待,直到鎖被釋放。
悲觀鎖在MySQL
、Java
有普遍的使用
MySQL
的讀鎖、寫鎖、行鎖等Java
的synchronized
關鍵字讀的多,衝突概率小,樂觀鎖。
寫的多,衝突概率大,悲觀鎖。
以爲有用記得收藏、點贊哦!