熊貓的博客 浪尖聊大數據 java
本文是粉絲投稿,原文地址:https://blog.csdn.net/qq_33540203/article/details/92597837
今天咱們來聊下線程中的悲觀鎖和樂觀鎖,首先提到"悲觀鎖","樂觀鎖"提到這兩個名詞,你們可能會先想到數據庫。注意啦,咱們這裏講的是多線程中的鎖,而不是數據庫中的鎖(沒聽過的童鞋,能夠百度瞭解下。大概思想同線程中的悲樂鎖思想差很少)。在Java中,經常使用Api提供的鎖就是synchronized和lock,以及CAS。不知道你們有沒有這樣的疑惑,我什麼場景下用哪把鎖最爲合適。
算法
synchronized和Lock都是悲觀鎖,它們認爲當使用數據的時候必定有其它線程來修改,因此在獲取數據的時候就會加鎖,確保不會被其它線程修改。數據庫
synchronized代碼塊:多線程
public synchronized void update() { //同步資源 }
Lock代碼塊:併發
public void update() { Lock lock = new ReentrantLock(); lock.lock(); try { //同步資源 } finally { lock.unlock(); } }
樂觀鎖,它認爲使用數據的時候不會有別的線程來修改數據,因此不會加鎖。只要在自身要進行update操做的時候,纔會去判斷以前的數據是否被別的線程修改了。若是沒有被修改則會修改爲功,相反則會修改不成功。這裏最典型的是java.util.concurrent併發包中的遞增操做就經過CAS自旋實現的。ide
CAS代碼塊性能
public class TestLock { AtomicInteger atomicInteger = new AtomicInteger(0); public int add() { return atomicInteger.incrementAndGet(); } }
什麼是CAS,CAS的全稱爲Compare And Swap(比較與交換),是一種無鎖算法。在不使用鎖(沒有線程被阻塞)的狀況下實現多線程之間的變量同步。大數據
總結: 這裏咱們能夠得出悲觀鎖適合寫操做多的場景,先加鎖能夠保證寫操做時數據正確。樂觀鎖適合讀操做多的場景,不加鎖的特色可以使其讀操做的性能大幅提高。不過從jdk1.8以後java已經對synchronized作了優化,性能上有了大幅度的提高。可是樂觀鎖CAS,也不是那麼十全十美,目前它存在三個三大問題。優化
1. ABA問題(JDK1.5以後已有解決方案):CAS須要在操做值的時候檢查內存值是否發生變化,沒有發生變化纔會更新內存值。可是若是內存值原來是A,後來變成了B,而後又變成了A,那麼CAS進行檢查時會發現值沒有發生變化,可是其實是有變化的。ABA問題的解決思路就是在變量前面添加版本號,每次變量更新的時候都把版本號加一,這樣變化過程就從「A-B-A」變成了「1A-2B-3A」。
2. 循環時間長開銷大:CAS操做若是長時間不成功,會致使其一直自旋,給CPU帶來很是大的開銷。
3. 只能保證一個共享變量的原子操做(JDK1.5以後已有解決方案):對一個共享變量執行操做時,CAS可以保證原子操做,可是對多個共享變量操做時,CAS是沒法保證操做的原子性的。
你們能夠把1和3的解決方案告訴我嗎?atom