[英]is Java HashSet thread-safe for read only?
如果我在通過Collections.unmodifiableSet()運行它后有一個HashSet實例,它是否是線程安全的?
我問這個,因為Set文檔聲明它不是,但我只是執行讀操作。
來自Javadoc:
請注意,此實現不同步。 如果多個線程同時訪問哈希集,並且至少有一個線程修改了該集,則必須在外部進行同步
閱讀不會修改一套,所以你很好。
如果以只讀方式使用, HashSet
將是線程安全的。 這並不意味着您傳遞給Collections.unmodifiableSet()
任何 Set都將是線程安全的。
想象一下這個contains
天真實現緩存最后檢查的值:
Object lastKey;
boolean lastContains;
public boolean contains(Object key) {
if ( key == lastKey ) {
return lastContains;
} else {
lastKey = key;
lastContains = doContains(key);
return lastContains;
}
}
顯然,這不是線程安全的。
這將是線程安全的,但僅僅是因為Collections.unmodifiableSet()
內部以安全的方式(通過final
字段)發布目標Set
。
請注意,通常諸如“只讀對象始終是線程安全的”之類的語句是不正確的,因為它們沒有考慮操作重新排序的可能性。
(理論上)可能的是,由於操作重新排序,在完全初始化對象並使用數據填充之前,對該只讀對象的引用將對其他線程可見。 要消除這種可能性,您需要以安全的方式發布對對象的引用,例如,通過將它們存儲在final
字段中,就像Collections.unmodifiableSet()
。
如果不改變它,每個數據結構都是線程安全的。
因為你必須改變HashSet才能初始化它,所以必須在初始化集合的線程和所有讀取線程之間進行一次同步。 你必須做一次 。 例如,當您將對不可修改集的引用傳遞給之前從未觸及它的新線程時。
是的,它對於並發讀訪問是安全的。 以下是文檔中的相關句子:
如果多個線程同時訪問哈希集,並且至少有一個線程修改了該集,則必須在外部進行同步。
它聲明如果at least one
線程修改它,您只需要同步。
我不相信它是線程安全的只是因為你運行Collections.unmodifiableSet()。 即使HashSet完全初始化並且您將其標記為不可修改,也不意味着其他線程可以看到這些更改。 更糟糕的是,在沒有同步的情況下,允許編譯器重新排序指令,這可能意味着讀取線程不僅會看到丟失的數據,而且還會看到處於奇怪狀態的散列集。 因此,您需要一些同步。 我相信解決這個問題的一種方法是將hashset創建為final並在構造函數中完全初始化它。 這是一篇關於JMM http://www.cs.umd.edu/~pugh/java/memoryModel/jsr-133-faq.html的好文章。 閱讀有關新JMM下最終字段如何工作的部分?
能夠看到字段的正確構造值是很好的,但如果字段本身是引用,那么您還希望代碼查看它指向的對象(或數組)的最新值。 如果您的字段是最終字段,則也可以保證。 因此,您可以擁有一個指向數組的最終指針,而不必擔心其他線程看到數組引用的正確值,但是數組內容的值不正確。 同樣,在這里“正確”,我們的意思是“對象的構造函數結束時的最新”,而不是“最新的可用值”。
如果永遠不會更改共享內存,則無需同步即可始終讀取。 使集合不可修改只會強制執行不能進行寫入的事實。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.