關於雙重檢測鎖的一種無volatile實現

本文已同步到http://liumian.win/2016/12/17/dcl-without-volatile/java

上一篇博客中提到雙重檢測鎖的無volatile實現,如何實現呢?那麼在這篇博客中來一探究竟吧~安全

無volatile的安全實現

先上代碼

/**
 * Created by liumian on 2016/12/13.
 */
public class DCL {

    private static DCL instance;
    
    private DCL(){}

    private DCL getInstance(){
        if (instance == null){              //1
            synchronized (DCL.class){       //2
                if (instance == null){      //3
                   DCL temp = new DCL();    //4
                   temp.toString();         //5
                   instance = temp;         //6
                }
            }
        }
        return instance;                    //7
    }
}

<!-- more -->多線程

再分析緣由

無volatile修飾的DCL歸根結底是對象的不安全發佈:對象尚未構造好,就將其發佈出去了。app

仔細與不安全的(無volatile)的DCL相比較,咱們在同步代碼塊裏面這三行代碼發生了改變:.net

DCL temp = new DCL();    
temp.toString();         
instance = temp;

對應三個步驟:線程

  1. 建立臨時變量
  2. 調用臨時變量的方法
  3. 將臨時變量的引用賦值給單例變量

爲何要引入臨時變量呢? 爲何要調用臨時變量的方法呢? 你們在內心確定會有這些疑問,別急,我來一個一個的回答。code

  1. 爲何要引入臨時變量? 引入臨時變量的目的是將對象的初始化(new、invokespecial)與賦值(astore)強行分開。可是僅僅經過一個臨時變量中轉是不夠的,請看下面這個問題的分析。對象

  2. 爲何要調用臨時變量的方法? 若是沒有調用臨時變量的方法這一行代碼:blog

    DCL temp = new DCL();   
    	instance = temp;

    並不能解決解決根本問題:對象的不安全發佈。由於JVM依然有可能對這三條指令:new、involvespecial以及兩條astore指令(分別對應的是賦值給temp,temp賦值給instance,由於線程內表現爲串行的語義的存在,這兩條賦值指令的順序不能改變),因此對於JVM來講那兩行代碼和這一行代碼並無特殊的地方:內存

    instance = new DCL();

如今問題的關鍵便落在了temp.toString(); 上一個問題的回答中咱們提到了解決問題的思路:將對象的初始化(new、invokespecial)與賦值(astore)強行分開。其實這行代碼起到的做用至關於一個內存屏障,將兩個操做(初始化和賦值)強行分開。 由於線程內表現爲串行的語義的存在,以及Happens-Before的第一條規則:程序次序規則(什麼是線程內表現爲串行的語義和程序次序規則請參看上一篇博客:從單例模式到Happens-Before),保證了在賦值操做(臨時變量賦值給單例變量)以前對象的初始化必定完成了。爲何?

重點來了

由於這段代碼在同步代碼塊中,因此保證了只有一條線程串行執行這幾行代碼,因此同時知足了線程內表現爲串行的語義程序次序規則

  1. 在線程內表現爲串行的語義中,JVM保證了臨時變量調用toString方法(或任意方法)時,該對象必定初始化完成了!請思考體會一下表現爲串行的含義。
  2. 而程序次序規則又保證了DCL temp = new DCL()Happens-Beforeinstance = temp,即前面的賦值操做必定對後面這個賦值操做可見

總結

經過線程內表現爲串行的語義程序次序規則這兩條規則的疊加使用,咱們作到了在不使用volatile關鍵字修飾的狀況下DCL爲線程安全。

經過這個例子可見,只要掌握了分析多線程安全的要點,找到緣由,咱們也能夠在解決問題時提出不同的解決方案。

相關文章
相關標籤/搜索