[英]Are all Thread methods (like getName/setName) thread-safe?
使用Thread
的方法(如setName
/ getName
和其他來自不同線程的其他方法是否安全? API沒有說什么,而是根據源代碼判斷
private char name[];
public final void setName(String name) {
checkAccess();
this.name = name.toCharArray();
}
public final String getName() {
return String.valueOf(name);
}
它似乎可能導致內存一致性錯誤。
Thread.getName()
是任何人都可以隨時查詢的屬性。 例如,監視器實用程序不斷查詢所有線程的名稱。 因此,該方法必須是線程安全的,否則,沒有明確的協議,誰可以安全地訪問它和何時。
盡管為什么Thread
使用char[]
保存其名稱一直令人費解,但是你提出了一個更重要的問題, getName()
顯然沒有正確同步。 如果一個線程執行setName("abcd")
,則另一個線程可能會觀察到getName()->"ab\\0\\0"
。
我將問題發布到並發興趣列表。 見http://cs.oswego.edu/pipermail/concurrency-interest/2013-March/010935.html
“API沒有說什么”
如果API沒有說什么,那么你永遠不能認為方法/類是線程安全的。 從源代碼中可以看出,acess to name
不是互斥的。
但對我來說,似乎該name
具有舊值或新值,兩者之間沒有任何內容,因此對於必須使用get/setName().
看起來是安全的get/setName().
對於初學者來說,如果一個線程調用setName
同時獲得name
不以某種方式同步,但也不能保證任何其他線程將看到新的價值。
其次, String.valueOf(char[])
遍歷name
。 這意味着如果在此迭代期間甚至設置了一個 name
的字符,則迭代線程可能會看到不一致的數據 - 原始char數組的第一個字符和另一個字符的最后一個字符。
在這種特殊情況下,它不是字符之一,而是指向char數組開頭的指針。 假設對數組的迭代通過將當前迭代索引添加到該指針的引用地址來計算要訪問的下一個單元,它確實也會導致不一致的數據。
** 編輯 **
關於第二個非安全方案,在閱讀了這個問題和答案之后 ,關於實際如何實現數組副本似乎不那么明顯 - 它依賴於平台。 這解釋了為什么String,valueOf(char[])
沒有記錄為線程安全的。 所以,無論如何,第二種情況仍然適用於非線程安全的。
如果線程對象在其他線程之間共享 (這可能是不尋常的,但仍然可能 - 如果您以這種方式編寫解決方案),那么它不是線程安全的。 它像任何其他類或對象一樣容易受到競爭條件的影響。
例:
Thread t1 = new SomeThread(); t1.start();
(new MyThread(t1, new Runnable() { public void run() {t1.setName("HELLO");} })).start();
(new MyThread(t1, new Runnable() { public void run() {t1.setName("GOODBYE");} })).start();
兩個線程訪問相同的線程對象t1。 不安全。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.