[英]Do I need to use volatile, if 2 different write and read thread will never alive at the same time
通過參考http://www.javamex.com/tutorials/synchronization_volatile.shtml , 由於附加規則3 ,我不確定在下列情況下是否需要使用volatile
關鍵字。
線程A寫入的新值是否會在“死”之后始終提交給主內存? 如果是,是否意味着如果滿足上述3個條件,我不需要volatile
關鍵字?
我懷疑在這種情況下需要volatile
。 根據需要, ArrayList可能會損壞。 由於一個線程可以執行insert和update size
成員變量。 之后,另一個線程(不兼容)可能會讀取ArrayList
的size
。 如果查看ArrayList
源代碼,則不ArrayList
size
聲明為volatile。
在ArrayList
JavaDoc中,只提到ArrayList
不能安全地用於多個線程同時訪問ArrayList實例 ,但不能讓多個線程在不同的時間訪問ArrayList實例 。
讓我使用以下代碼來解決此問題
public static void main(String[] args) throws InterruptedException {
// Create and start the thread
final ArrayList<String> list = new ArrayList<String>();
Thread writeThread = new Thread(new Runnable() {
public void run() {
list.add("hello");
}
});
writeThread.join();
Thread readThread = new Thread(new Runnable() {
public void run() {
// Does it guarantee that list.size will always return 1, as this list
// is manipulated by different thread?
// Take note that, within implementation of ArrayList, member
// variable size is not marked as volatile.
assert(1 == list.size());
}
});
readThread.join();
}
是的,您仍然需要使用volatile(或其他形式的同步)。
原因是兩個線程可以在不同的處理器上運行,即使一個線程在另一個線程開始之前已經完成了很長時間,也不能保證第二個線程在進行讀取時會獲得最新的值。 如果該字段未標記為volatile並且未使用其他同步,則第二個線程可以獲取在其運行的處理器上本地緩存的值。 理論上緩存的值可能在很長一段時間內都是過時的,包括在第一個線程完成之后。
如果使用volatile,則將始終將值寫入主內存並從主內存中讀取,從而繞過處理器的緩存值。
不,你可能不需要它。 盡管Mark Byers的回答開始相當准確,但它是有限的。 synchronized和volatile不是在線程之間正確傳遞數據的唯一方法。 還有其他一些較少談論“同步點”。 具體而言,線程開始和線程結束是同步點。 但是,啟動線程B的線程必須已經識別出線程A已完成(例如,通過連接線程或檢查線程的狀態)。 如果是這種情況,則變量不需要是volatile。
可能是的,除非您手動創建內存屏障。 如果A設置變量,並且B決定從某個注冊表中取出oit,那么就會出現問題。 因此,您需要一個內存屏障,隱式(鎖定,易失性)或顯式。
http://java.sun.com/docs/books/jls/third_edition/html/memory.html#17.4.4
線程T1中的最終操作與另一個檢測到T1已終止的線程T2中的任何操作同步。 T2可以通過調用T1.isAlive()或T1.join()來完成此操作。
因此,可以在不使用volatile的情況下實現目標。
在許多情況下,當存在明顯的時間依賴性時,同事正在由人員進行同步,並且應用程序不需要額外的同步。 不幸的是,這不是規則,程序員必須仔細分析每個案例。
一個例子是Swing工作者線程。 人們會在工作線程中進行一些計算,將結果保存到變量,然后引發事件。 然后,事件線程將從變量中讀取計算結果。 應用程序代碼不需要顯式同步,因為“引發事件”已經進行了同步,因此工作線程的寫入在事件線程中是可見的。
一方面,這是一種幸福。 另一方面,許多人不理解這一點,他們省略了同步只是因為他們從未想過這個問題。 他們的節目恰好是正確的......這一次。
如果線程A在線程B開始讀取之前肯定死亡,則可以避免使用volatile
例如。
public class MyClass {
volatile int x = 0;
public static void main(String[] args) {
final int i = x;
new Thread() {
int j = i;
public void run() {
j = 10;
final int k = j;
new Thread() {
public void run() {
MyClass.x = k;
}
}.start();
}
}.start();
}
}
但問題是,無論Thread啟動哪個線程B,現在都需要線程A寫入的值已經改變,並且不使用自己的緩存版本。 最簡單的方法是讓線程A生成線程B.但是如果線程A在生成線程B時沒有別的事情可做,那么這似乎有點無意義(為什么不使用相同的線程)。
另一個替代方案是,如果沒有其他線程依賴於此變量,則可能線程A可以使用volatile變量初始化局部變量,執行它需要執行的操作,然后最終將其局部變量的內容寫回volatile變量。 然后,當線程B啟動時,它從volatile變量初始化其局部變量,然后僅從其局部變量讀取。 這應該大大減少保持volatile變量同步所花費的時間。 如果這個解決方案似乎不可接受(因為其他線程寫入volatile變量或其他),那么你肯定需要聲明變量volatile。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.