簡體   English   中英

是Java HashSet線程安全的只讀?

[英]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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM