繁体   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