2016-08-20 51 views
0

考慮從Java併發的片段在行爲─一點澄清volatile關鍵字

// Unsafe publication 
public Holder holder; 

public void initialize(){ 
    holder = new holder(42); 
} 

public class Holder{ 
    private int n; 

    public Holder(int n) { 
     this.n = n; 
    } 

    public void assertSanity(){ 
     if (n != n) 
      throw new AssertionError("This statement is false."); 
    } 
} 

一經書的作者提出的解決方案是 -

public static Holder holder = new Holder(42); 

如果唯一的要求是防止AssertionError,那麼這也可以很好地工作 -

private final int n; 

我的問題是後續的評論對這段計算器thread約翰Vint-

其實,宣告成員字段揮發性仍犯規保證 出版物持有者可見之前。您可以看看 ConcurrentHashMap的私有方法readUnderLock,其中考慮到了這個細微差別 。雖然宣稱持有人是揮發性的。

說得簡單的話,他特此提示2東西 -

public volatile Holder holder; 

public void initialize(){ 
    holder = new holder(42); 
} 

在上述解決方案將很好地工作?如果將引用聲明爲volatile,是否確保安全對象發佈?數組也是對象。聲明數組引用不會使其元素線程安全。

而且爲什麼由作者 -

public class Holder { 
private volatile int n; 

的建議,宣佈成員字段揮發性仍犯規保障 公佈持有人前,這是不行的可見

即使作爲成員字段已被聲明爲volatile,其保證條件n != n將始終爲false,因此沒有AssertionError。請建議。

回答

2

雖然使用volatile會幫助您建議,但它不會幫助您可能碰巧嘗試使用的許多其他情況。即錯誤地使用volatile非常容易,所以除非您確定知道哪些操作將被使用,否則很難鼓勵。

如果對一個對象的引用聲明爲volatile,它是否確保安全對象發佈?

這非常依賴於操作的順序和類型。在這種情況下,寫

this.n = n; 
// and then 
holder = ... 

holder寫確保在寫this.n必須是可見假設你還做

Holder h = holder; // read barrier 
// n must be set. 
int n = this.n; 

聲明的成員字段之前持有揮發性仍犯規保證出版物可見

我不同意這種情況。一旦在另一個線程中獲得了holder,讀取n將不會在您讀取volatile變量時看到初始化的值。這是因爲只有在n被初始化後才設置holder

+0

感謝。但是這個具體案例不是作者錯誤的。 –

+0

@ShirgillFarhanAnsari我同意,一般來說'volatile'不提供你需要的保證,但在這種特定情況下,它會發生作用。 –

+0

再次感謝,但沒有得到您的第二個代碼片段持有人h =持有人;//讀屏障的觀點。請詳細說明。 –

0

試試這個

public class main { 
public volatile static Holder holder; 
public static void main(String[] args) { 
    // TODO Auto-generated method stub 
    // Unsafe publication 
    initialize(); 
    holder.assertSanity(99); 
} 
public static void initialize(){ 
    holder = new Holder(42); 
} 
} 

Holder.java

public class Holder { 

private volatile Integer n; 
    public Holder(Integer n) { 
     this.n = n; 
    } 

    public void assertSanity(Integer n){ 
     if (!((Object)this.n).equals((Object)n)) 
      throw new AssertionError("This statement is false."); 
    } 

    public Integer getN() { 
     return n; 
    } 

    public void setN(Integer n) { 
     this.n = n; 
    } 

}