Java併發鎖(一):悲觀鎖與樂觀鎖

Java併發鎖(一):悲觀鎖與樂觀鎖

熊貓的博客 浪尖聊大數據 java

本文是粉絲投稿,原文地址:https://blog.csdn.net/qq_33540203/article/details/92597837
今天咱們來聊下線程中的悲觀鎖和樂觀鎖,首先提到"悲觀鎖","樂觀鎖"提到這兩個名詞,你們可能會先想到數據庫。注意啦,咱們這裏講的是多線程中的鎖,而不是數據庫中的鎖(沒聽過的童鞋,能夠百度瞭解下。大概思想同線程中的悲樂鎖思想差很少)。在Java中,經常使用Api提供的鎖就是synchronized和lock,以及CAS。不知道你們有沒有這樣的疑惑,我什麼場景下用哪把鎖最爲合適。
Java併發鎖(一):悲觀鎖與樂觀鎖算法

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(比較與交換),是一種無鎖算法。在不使用鎖(沒有線程被阻塞)的狀況下實現多線程之間的變量同步。大數據

Java併發鎖(一):悲觀鎖與樂觀鎖

總結: 這裏咱們能夠得出悲觀鎖適合寫操做多的場景,先加鎖能夠保證寫操做時數據正確。樂觀鎖適合讀操做多的場景,不加鎖的特色可以使其讀操做的性能大幅提高。不過從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

相關文章
相關標籤/搜索