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