2012-03-10 116 views
2

我讀過,你應該使用volatile當一個線程訪問一個變量,以確保線程看到正確的值,但這也適用於變量在方法中使用時嗎?方法中是否需要「易失性」?

示例代碼:

public class Limiter 
{ 
    int max = 0; 

    public synchronized void doSomething() 
    { 
     max++; 
     if(max < 10) 
      System.out.println("Work"); 

     System.out.println(max); 
    } 

} 

它是安全的假設,如果多線程調用doSomething,然後max將被設置爲相同的狀態時,前一個線程調用的方法?

由於doSomething()是同步的,我知道只有一個線程可以修改max,但是當下一個線程調用它時會發生什麼? max可以是不同的值,因爲它不使用volatile?或者它是安全的,因爲「限制器」實例自己修改它?

回答

7

volatile是一個字段,而不是它使用的一部分的聲明的一部分。將局部變量聲明爲volatile是沒有意義的,因爲局部變量不會被不同的線程看到。

就你而言,只要沒有非同步方法中的代碼可以訪問max - 內存模型基本上可以確保只要所有代碼獲取/釋放同一監視器「守護」一個變量,所有線程將看到一致的值序列。 (除此之外,每個線程都必須在訪問該值之前獲取監視器,這意味着一次只能有一個線程訪問該值 - 您可以編寫「線程X」的顯示順序時間t0-t1,線程Y在時間t4-t5有顯示器「等)

2

我讀過,當線程訪問變量以確保線程看到正確的值時,應該使用volatile,但是這也適用於在方法內使用變量的情況嗎?

這在多個方面都不準確*

首先:volatile只能在字段上使用。它不能用於其他類型的變量;即局部變量或參數。 (原因:這是毫無意義的,因爲其他類型的變量只對一個線程可見)。

其次:volatile語義適用於是否使用方法調用。 (或塊)。使用​​方法(或塊)。但是正確使用​​通常以全部爲條件使用同步構造來執行訪問和更新。任何非同步訪問或更新可能呈現程序(作爲一個整體)不正確。

最後:volatile方式訪問到外地會看到該字段的值的最新值。這不足以保證的正確性。例如:

public Counter { 
    private volatile int count; 

    public void increment() { 
     // This is NOT correct. 
     count++; 
    } 
} 

的原因,上面的例子是不正確的是count++不是原子。它實際上意味着(字面上)count = count + 1,而另一個線程可能會在訪問它的當前線程和寫回更新值之間更改count。這會導致偶爾丟失的增量。

這是很容易看到,該聲明maxvolatile,並擺脫了​​關鍵字的代碼的版本將完全相同的原因是不正確的。您目前的版本在這方面更爲正確。但是,它仍然不完全正確,因爲沒有任何東西阻止其他類(在同一個包中)訪問或更新max。如果這是在一個不同的線程中完成的,那麼除了漏洞抽象之外,你還會遇到一個潛在的併發問題。


因此,要回答你的問題:

它是安全的假設,如果多線程調用DoSomething的,那麼最多將被設置爲相同的狀態時,前一個線程調用的方法?

不完全是因爲漏洞的抽象。 (聲明max是私有修復了這個。)

因爲DoSomething的()是同步的,我知道,只有一個線程可以修改最大,但是當一個線程調用它會發生什麼?

​​塊可確保在同一對象上同步的下一個線程將看到這些更新。 (如何實現平臺特定...)

最大可以是不同的值,因爲它不使用易失性?

不......模泄漏抽象問題。

或者它是安全的,因爲「限制器」實例修改它本身?

這其實是無關這個代碼的線程安全/正確性。重要的是同步,而不是自我修改。


*至少,你的你已經被你已經閱讀明白了總結是不正確的。對於我們所知的一切,您閱讀的原文可能是正確的。


UPDATE

我讀談論字段中的一部分(如由線程訪問的變量)。對困惑感到抱歉。我想知道的是,它是否也適用於由線程調用的對象中的方法使用的所有變量。

這適用於線程讀取和/或寫入的對象的所有字段都由同步區域覆蓋。實際上,它適用於其他對象的字段,以及在該區域中讀取/寫入的數組的元素。 (對於不是字段的變量是「無意的」,因爲沒有其他線程可以看到它們。)

但是,需要注意的是,它只適用於同步點。如果第二個線程沒有正確同步,所有投注都關閉。

+0

我讀的部分是關於字段(如在線程可訪問的變量中)。對困惑感到抱歉。我想知道的是,它是否也適用於由線程調用的對象中的方法使用的所有變量。 – Mstr 2012-03-11 16:57:38

相關問題