簡體   English   中英

Hashtable:為什么get方法同步?

[英]Hashtable: why is get method synchronized?

我知道Hashtable是同步的,但為什么它的get()方法是同步的?

它只是一種讀取方法嗎?

如果讀取未同步,則可以在執行讀取期間修改Hashtable。 可以添加新元素,底層數組可能變得太小而且可能被更大的元素替換,等等。如果沒有順序執行,則很難處理這些情況。

但是,即使在另一個線程修改Hashtable時get不會崩潰, synchronized關鍵字還有另一個重要方面,即緩存同步。 讓我們使用一個簡化的例子:

class Flag {
  bool value;

  bool get() { return value; } // WARNING: not synchronized
  synchronized void set(bool value) { this->value = value; }
}

set是同步的,但get不是。 如果兩個線程A和B同時讀寫此類,會發生什么?

1. A calls read
2.                 B calls set
3. A calls read

在第3步是否保證A看到線程B的修改?

不,它不是,因為A可以在不同的核心上運行,該核心使用單獨的緩存,其中舊值仍然存在。 因此,我們必須強制B將內存傳遞給其他核心,並強制A獲取新數據。

我們如何執行它? 每次,線程進入並離開同步塊,執行隱式內存屏障 內存屏障強制更新緩存。 但是,要求寫入者和閱讀者都必須執行內存屏障。 否則,信息未正確傳達。

在我們的示例中,線程B已經使用了synchronized方法set ,因此在方法結束時傳遞其數據修改。 但是,A沒有看到修改后的數據。 解決方案是使get同步,因此它被迫獲取更新的數據。

看看Hashtable源代碼,你可以想到很多競爭條件可能導致不同步的get()

(我正在閱讀JDK6源代碼)

例如, rehash()將創建一個空數組,並將其分配給實例var table ,並將舊表中的條目放入新表中。 因此,如果在空數組賦值之后發生get ,但在實際將條目放入其中之前,即使它在表中也找不到您的密鑰。

另一個例子是,循環迭代通過表索引處的鏈表,如果在迭代中間,則重新發生。 即使它存在於哈希表中,您也可能無法找到該條目。

Hashtable是同步的,意味着整個類是線程安全的

Hashtable ,不僅get()方法是同步的,而且還有許多其他方法。 特別是put()方法就像Tom說的那樣同步。

必須將read方法同步為write方法,因為它將確保變量的可見性和一致性。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

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