文章目錄
- `volatile` 修飾數組引用的含義
- `volatile` 對數組元素無效
- 總結
- 如何讓數組元素也具有 `volatile` 特性?
當用 volatile
關鍵字修飾一個數組時,它只保證數組引用的可見性和部分原子性,而不保證數組元素的可見性和原子性。
換句話說,volatile
作用于數組變量本身,而不是數組中的每個元素。
volatile
修飾數組引用的含義
當你聲明一個數組為 volatile
時,比如:
private volatile String[] arr = new String[10];
這里的 volatile
關鍵字確保了以下兩點:
-
可見性 (Visibility): 當一個線程修改了
arr
這個數組的引用時(例如,讓它指向一個新的數組),這個修改會立刻對其他所有線程可見。// 線程 A arr = new String[20]; // 這個賦值操作會立刻被其他線程看到// 線程 B // 能立即讀到 arr 指向了一個新的長度為 20 的數組
-
防止指令重排序 (Instruction Reordering):
volatile
會提供一個內存屏障,防止編譯器和處理器對arr
的讀寫操作進行重排序,確保了代碼執行的順序性。
volatile
對數組元素無效
最重要的一點是,volatile
不會 將其效果傳遞給數組的元素。對數組元素的修改,例如:
// 線程 A
arr[0] = "Hello";
這個修改不具備 volatile
的特性。其他線程可能無法立即看到 arr[0]
的值變成了 “Hello”。對數組元素的讀寫操作仍然可能存在數據競爭和可見性問題。
總結
操作 | 是否受 volatile 影響 | 解釋 |
---|---|---|
arr = new String[20]; (修改數組引用) | 是 ? | volatile 保證了對數組引用的修改在多線程間的可見性。 |
arr[0] = "new value"; (修改數組元素) | 否 ? | volatile 不會影響數組內部元素,對元素的修改不保證多線程間的可見性。 |
String s = arr[0]; (讀取數組元素) | 否 ? | 同樣,讀取元素時也可能讀到舊的、未同步的數據。 |
如何讓數組元素也具有 volatile
特性?
如果你需要讓數組的每個元素都具有 volatile
的語義,你應該使用 java.util.concurrent.atomic
包下的 AtomicReferenceArray
類。
AtomicReferenceArray
提供了一種方式,使其內部的每個元素都支持原子的、線程安全的操作。
示例:
import java.util.concurrent.atomic.AtomicReferenceArray;// 使用 AtomicReferenceArray 替代 volatile 數組
private AtomicReferenceArray<String> atomicArr = new AtomicReferenceArray<>(10);// 線程 A - 安全地設置元素值
atomicArr.set(0, "Hello");// 線程 B - 安全地獲取元素值
String value = atomicArr.get(0);
在這種情況下,對 atomicArr
中任何一個元素的修改都會對其他線程立即可見。