volatile與synchronized詳解

文章目錄:java

1.簡單理解Volatile和synchronized緩存

2.Volatile詳解多線程

3.synchronized詳解app

4.Volatile與synchronized的區別與聯繫jvm

 

1.簡單理解Volatile和synchronized:優化

synchronized:當被synchronized修飾時,synchronized會鎖定當前變量,只有當前線程可以訪問該變量,其餘線程會被阻塞。spa

volatile:當volatile修飾變量時,編譯器對此變量的讀寫操做不作任何優化,每次都會去內存去讀,寫也是寫到內存,不作任何的緩存優化線程

volatile,final,synchronized均可以實現可見性。code

2.Volatile詳解對象

volatile可見性原理

可見性:任何線程能立刻看到它的結果

volatile的本質是告訴jvm這個變量是在寄存器中的值是不肯定的,加入volatile關鍵字之後,保存數據會同步到主內存中,而另外一端讀數據時也會從主內存中讀取,volatile使用cpu的緩存鎖來保證可見性。

volatile禁止指令重排序

指令重排序的目的: 提升cpu運算效率

cpu提升利用率的過程:進程 -> 線程 -> 指令

指令重排序究竟是什麼?

舉個栗子:寫代碼每一行都是一個指令,有的指令運行時間比較長,不能讓其餘指令排隊等着,這時對指令進行從新排序,來提升運行效率

 

無論怎麼重排序,單線程都遵循 as-if-serial語義,而多線程遵循 happen-before

講清楚指令重排序了,volatile如何防止指令重排?

Volatile變量在賦值後會有一個lock add命令,這個命令至關於內存屏障,重排序時不能把屏障後的指令重排序到屏障以前。

volatile使用案例

案例1

在下面這個單例模式下,會指令重排序,若是這時多線程訪問,這時尚未初始化對象,會發生不完整實例。 如圖2-1

使用volatile修飾 instance 防止這種問題發生

public class VolatileDemo {

    private  volatile static  VolatileDemo instance;

    private VolatileDemo(){}
   
    /*
     * 懶漢模式 double check
     * 不完整實例,指令重排序致使多線程訪問發生不完整實例,
     * 解決辦法:    private volatile static  VolatileDemo instance;
     * 防止指令重排序
     * */

    public static VolatileDemo getInstance2(){
        if (instance == null ){
            synchronized (VolatileDemo.class){
                if (instance == null){
                    instance = new VolatileDemo();
                }
            }
        }
        return instance;
    }
}

 圖2-1

案例2

volatile int i;
public void add{
    i++;
}

這裏先要讀i值 ,而後++,又同步。 再多線程操做時會出錯,原理同案例1,有關指令重排序的問題致使的。

3.synchronized詳解

當被synchronized關鍵字修飾的代碼塊在被編譯成字節碼的時候,會在該代碼塊開始和結束的地方加入 monitorenter 和 moniterexist 指令,任何對象都有一個monitor相關聯,當一個monitor被持有後,他就處於鎖定狀態,當線程執行到monitorenter指令時,會獲嘗試獲取對象對應的monitor的全部權,即獲取對象的鎖。monitor指令如圖3-1

                       圖3-1

虛擬機在執行這兩個命令的時候,會檢查對象的鎖狀態是否爲空或當前線程是否已經擁有對象的鎖,

若是是 則對象鎖的計數器加 1 ,直接進入同步代碼,

若是不是,則當前線程阻塞等待,等待鎖釋放。

4.Volatile與synchronized的區別與聯繫

(1)volatile,final,synchronized均可以實現可見性

(2)volatile的本質是告訴jvm這個變量是在寄存器中的值是不肯定的,須要從主存中讀取。

(3)synchronized是鎖定當前變量,只有當前線程可以訪問該變量,其餘線程被阻塞。

(4)volatile僅能實現變量的修改可見性,不具有原子性,而synchronized能夠實現變量的修改可見性和原子性

(5)volatile標記的變量不會被編譯器優化,而synchronized能夠(禁止指令重排序)

(6)volatile使用在變量級別,而synchronized可使用在變量和方法

(7)volatile不會阻塞線程,而synchronized可能會

相關文章
相關標籤/搜索