2012-03-26 42 views
7

從書的「Java併發編程實踐」第26頁:如何理解「變量在使用volatile關鍵字時不參與與其他狀態變量的不變量」?

可以使用,只有當以下所有條件都滿足volatile變量:

  • 寫入變量,不取決於它的當前值或者你可以確保只有一個線程不斷更新的價值;

  • 變量不參與不變量與其他狀態變量;和

  • 當訪問變量時,不需要鎖定任何其他原因。

如何理解「使用volatile關鍵字時,變量不參加與其他狀態變量不變」?

+0

一些更多的上下文將是有用的,否則我只是猜測它可能意味着什麼。 – 2012-03-26 08:14:54

+0

對不起,我現在添加了上下文 – 2012-03-26 08:37:35

+0

在我的書中它是39頁 – gstackoverflow 2017-02-09 14:47:11

回答

15

「不變」的簡單定義:在對象的生命週期中始終爲真的條件

Volatile variables do not share the atomicity features of synchronized blocks.

這就是爲什麼你不能在一個擁有多個變量的不變量的類中使用它們。

例如,假設您有一個class來模擬兩個變量描述的時間間隔:startend。不變條件可能是start總是小於或等於end。如果兩個變量(如示例)都被聲明爲volatile,那麼您可以依賴volatile的可見性功能,但不能確定在涉及兩個變量的變化過程中,始終滿足不變量。想想:

public void setInterval(Date newStart, Date newEnd) 
{ 
// Check if inputs are correct 

// Here the object state is valid 
start = newStart; 

// If another thread accesses this object now it will 
// see an invalid state because start could be greater than end 

end = newEnd; 
// Here the object state is valid again 
} 

在這種情況下,您可以確定更改對每個線程均可見,但在兩條指令的中間,對象狀態可能無效。因爲它可以被其他線程訪問(記住這是一個簡單的例子,所以可能但不可能),那麼不變條件「開始<結束」可能被破壞。

這就是爲什麼揮發性的使用以某種方式阻礙了一小組定義好的模式之外。只有在滿足以下條件時才應使用易變變量:

  • 該變量不涉及與其他變量(基於上述原因)的不變量。
  • 要寫入變量的值不取決於其當前值。

例如表達int a = i++;不是原子,則它不會 - 嚴格地說 - 線程安全的,因爲它會改寫是這樣的:

int temp = i; 
i = i + 1; 
int a = temp; 

爲了讓原子從一個線程點,你可以想像這樣的一類:

public class MyAtomicInteger 
{ 
    public synchronized increment() 
    { 
    x = x + 1; 
    } 

    private int x; 
} 

當然它存在一個真正的impleme這個AtomicInteger的實例,它是包java.util.concurrent.atomic的一部分,它爲無鎖併發編程提供了一些簡單的基本例程。

+0

有一個錯誤:它不是'i = i + 1',而是'i = temp + 1'在你的'i'增量樣本中,否則會導致因爲'i = i + 1'與'i ++'操作相同,所以無限的子狀態。 – Mik378 2012-11-15 11:34:20

+0

@ Mik378在增量「i == temp」之前,所以「i = i + 1」等同於「i = temp + 1」。這是如何「++」擴展而不是「+」,那麼「i + 1」將不會再次擴大 – 2012-11-15 11:39:57

+0

瞭解,謝謝。 – Mik378 2012-11-15 11:50:13