樂觀鎖和悲觀鎖都是用於解決並發場景下的數據競爭問題,但是卻是兩種完全不同的思想。它們的使用非常廣泛,也不局限於某種編程語言或數據庫。
樂觀鎖的概念
所謂的樂觀鎖,指的是在操作數據的時候非常樂觀,樂觀地認為別人不會同時修改數據,因此樂觀鎖不會上鎖,只有在執行更新的時候才會去判斷在此期間別人是否修改了數據,如果別人修改了數據則放棄操作,否則執行操作。
悲觀鎖的概念
所謂的悲觀鎖,指的是在操作數據的時候比較悲觀,悲觀地認為別人一定會同時修改數據,因此悲觀鎖在操作數據時是直接把數據上鎖,直到操作完成之后才會釋放鎖,在上鎖期間其他人不能操作數據。
樂觀鎖的實現方式
樂觀鎖的實現方式主要有兩種,一種是CAS(Compare and Swap,比較並交換)機制,一種是版本號機制。
CAS機制
CAS操作包括了三個操作數,分別是需要讀取的內存位置(V)、進行比較的預期值(A)和擬寫入的新值(B),操作邏輯是,如果內存位置V的值等於預期值A,則將該位置更新為新值B,否則不進行操作。另外,許多CAS操作都是自旋的,意思就是,如果操作不成功,就會一直重試,直到操作成功為止。
版本號機制
版本號機制的基本思路,是在數據中增加一個version字段用來表示該數據的版本號,每當數據被修改版本號就會加1。當某個線程查詢數據的時候,會將該數據的版本號一起讀取出來,之后在該線程需要更新該數據的時候,就將之前讀取的版本號與當前版本號進行比較,如果一致,則執行操作,如果不一致,則放棄操作。
悲觀鎖的實現方式
悲觀鎖的實現方式也就是加鎖,加鎖既可以在代碼層面(比如Java中的synchronized關鍵字),也可以在數據庫層面(比如MySQL中的排他鎖)。
樂觀鎖與悲觀鎖的優缺點和使用場景
樂觀鎖和悲觀鎖並沒有優劣之分,它們有各自適合的場景。
功能限制
樂觀鎖與悲觀鎖相比,適用的場景受到了更多的限制,無論是CAS機制還是版本號機制。
比如,CAS機制只能保證單個變量操作的原子性,當涉及到多個變量的時候,CAS機制是無能為力的,而synchronized卻可以通過對整個代碼塊進行加鎖處理;再比如,版本號機制如果在查詢數據的時候是針對表1,而更新數據的時候是針對表2,也很難通過簡單的版本號來實現樂觀鎖。
競爭激烈程度
在競爭不激烈(出現並發沖突的概率比較小)的場景中,樂觀鎖更有優勢。因為悲觀鎖會鎖住代碼塊或數據,其他的線程無法同時訪問,必須等待上一個線程釋放鎖才能進入操作,會影響並發的響應速度。另外,加鎖和釋放鎖都需要消耗額外的系統資源,也會影響並發的處理速度。
在競爭激烈(出現並發沖突的概率較大)的場景中,悲觀鎖則更有優勢。因為樂觀鎖在執行更新的時候,可能會因為數據被反復修改而更新失敗,進而不斷重試,造成CPU資源的浪費。
樂觀鎖是否會加鎖
樂觀鎖本身是不加鎖的,只有在更新的時候才會去判斷數據是否被其他線程更新了,比如AtomicInteger便是一個例子。但是有時候樂觀鎖可能會與加鎖操作合作,比如MySQL在執行更新數據操作的時候會加上排他鎖。因此可以理解為樂觀鎖本身是不加鎖的,只有在更新數據的時候才有可能會加鎖。
CAS的缺點
CAS的缺點主要有ABA問題、高競爭下的開銷問題和本身的功能限制。
ABA問題
所謂的ABA問題,指的就是一個線程在操作數據的時候,有別的線程對數據進行了一系列操作,但是在該線程重新讀取該數據的時候,被修改過的數據卻和該線程一開始讀取的數據一致,該線程不會知道該數據已經被修改過了,然后CAS操作就被判斷是成功了。
ABA問題在一些場景下可能不會造成什么危害,但是在某些場景中卻可能會造成隱患。比如CAS操作的是棧頂的數據,棧頂的數據雖然經過兩次(或多次)變化后又恢復了原值,但是棧卻可能是發生了變化,棧中數據的變化就可能會引發一些問題。
對於ABA問題,比較有效的方案是引入版本號。只要內存中的值發生變化,版本號就加1,在進行CAS操作的時候不僅比較內存中的值,也比較版本號,只有當二者都沒有變化的時候,CAS操作才能執行成功。Java中的AtomicStampedReference類便是適用版本號來解決ABA問題的。
高競爭下的開銷問題
在並發沖突的概率較大的高競爭場景下,如果CAS操作一直失敗,就會一直重試,造成CPU開銷大的問題。針對這個問題,一個簡單的思路是引入退出機制,如果重試次數超過一定閾值,就強制失敗退出。當然了,最好是避免在高競爭的場景下使用樂觀鎖。
自身的功能限制
CAS的功能是比較受限的,比如CAS只能保證單個變量(或者說單個內存值)操作的原子性。這就意味着原子性不一定能保證線程安全,當涉及到多個變量(或者說多個內存值),CAS也是無能為力。除此之外,CAS的實現需要硬件層面處理器的支持,在Java中普通的用戶是無法直接使用的,只有借助atomic包下的原子類才能使用,靈活性有限。
"新朋友不知道舊脾氣,老朋友不知道新生活。"