Java的四種同步方式你瞭解嗎?

一、voliatejava

voliate賦予變量在多線程中的可見性,只能做用於變量,非堵塞。java內存模型(以下圖)描述了多線程之間信息交換和同步的方式:每一個線程都從主內存load一份數據到本身的工做內存,線程對變量的讀寫操做都是在工做內存中進行的,而後在save到主內存。bash

若是多線程同時操做主內存贊成拷貝變量a,那麼就可能致使變量的值亂掉,voliate保證了voliate變量值修改後的新值當即同步到主內存,每次使用變量也都從主內存刷新數據,即保證了數據在線程間的可見性以及禁止指令重排序。多線程

二、synchronized異步

synchronize經過加鎖堵塞的方式來實現同步,能夠修飾變量,方法以及代碼塊.性能

Synchronized 的語義底層是經過一個 Monitor 的對象來完成,ui

每一個對象有一個監視器鎖(Monitor),當 Monitor 被佔用時就會處於鎖定狀態。 線程執行 Monitorenter 指令時嘗試獲取 Monitor 的全部權,過程以下: 若是 Monitor 的進入數爲 0,則該線程進入 Monitor,而後將進入數設置爲 1,該線程即爲 Monitor 的全部者。spa

若是線程已經佔有該 Monitor,只是從新進入,則進入 Monitor 的進入數加 1。線程

若是其餘線程已經佔用了 Monitor,則該線程進入阻塞狀態,直到 Monitor 的進入數爲 0,再從新嘗試獲取 Monitor 的全部權。code

執行 Monitorexit 的線程必須是 Objectref 所對應的 Monitor 的全部者。 指令執行時,Monitor 的進入數減 1,若是減 1 後進入數爲 0,那線程退出 Monitor,再也不是這個 Monitor 的全部者orm

三、AtomicInteger

AtomicInteger的本質:自旋鎖+Unsafe的CAS原子操做,非堵塞同步方式(同步指的是一直等待結果,非堵塞是指能夠作其餘的事情,並不釋放cpu資源。)。

網上的一則故事比較生動地講堵塞與同步

故事:老王燒開水。
出場人物:老張,水壺兩把(普通水壺,簡稱水壺;會響的水壺,簡稱響水壺)。
老王想了想,有好幾種等待方式
1.老王用水壺煮水,而且站在那裏,無論水開沒開,每隔必定時間看看水開了沒。-同步阻塞
老王想了想,這種方法不夠聰明。
2.老王仍是用水壺煮水,再也不傻傻的站在那裏看水開,跑去寢室上網,可是仍是會每隔一段時間過來看看水開了沒有,水沒有開就走人。-同步非阻塞
老王想了想,如今的方法聰明瞭些,可是仍是不夠好。
3.老王此次使用高大上的響水壺來煮水,站在那裏,可是不會再每隔一段時間去看水開,而是等水開了,水壺會自動的通知他。-異步阻塞
老王想了想,不會呀,既然水壺能夠通知我,那我爲何還要傻傻的站在那裏等呢,嗯,得換個方法。
4.老王仍是使用響水壺煮水,跑到客廳上網去,等着響水壺本身把水煮熟了之後通知他。-異步非阻塞
老王豁然,這下感受輕鬆了不少。
對於互斥鎖這樣的悲觀鎖,若是資源已經被佔用,資源申請者只能進入睡眠狀態。可是自旋鎖是樂觀鎖,它不會引發調用者睡眠,若是自旋鎖已經被別的執行單元保持,調用者就一直循環在那裏看是否該自旋鎖的保持者已經釋放了鎖,"自旋"一詞就是所以而得名。
複製代碼

優勢:經過CAS保證了原子性

缺點:消耗CPU性能

四、ReentrantLock

重入鎖底層實現是AbstractQueuedSynchronizer,簡稱AQS。synchronized是基於JVM層面實現的,而Lock是基於JDK層面實現的。相比synchronized,ReentrantLock能夠進行鎖的超時和中斷設置。重入性是指若是以獲取鎖的線程再次去獲取鎖,那麼就會獲取鎖成功,獲取鎖成功次數加1,後面釋放鎖鎖的次數必須等於以前成所獲取鎖的的次數,那麼該鎖纔算徹底釋放。

/**
 * Performs non-fair tryLock.  tryAcquire is implemented in
 * subclasses, but both need nonfair try for trylock method.
 */
final boolean nonfairTryAcquire(int acquires) {  //獲取鎖
    final Thread current = Thread.currentThread();
    int c = getState();
    if (c == 0) {  //鎖是否被佔用
        if (compareAndSetState(0, acquires)) {
            setExclusiveOwnerThread(current);
            return true;
        }
    }
    else if (current == getExclusiveOwnerThread()) {  //佔用鎖的線程是否時當前線程
        int nextc = c + acquires;  //若是是,則獲取鎖次數+1
        if (nextc < 0) // overflow
            throw new Error("Maximum lock count exceeded");
        setState(nextc);
        return true;
    }
    return false;
}
protected final boolean tryRelease(int releases) {  //釋放鎖
    int c = getState() - releases;  //上輩子造的孽,一個個減吧
    if (Thread.currentThread() != getExclusiveOwnerThread())  //佔用鎖的線程是否時當前線程
        throw new IllegalMonitorStateException();
    boolean free = false;
    if (c == 0) {  
        free = true;  //真正釋放了
        setExclusiveOwnerThread(null);   //真正釋放了
    }
    setState(c);
    return free;
}
複製代碼
相關文章
相關標籤/搜索