Hashtable和Collections.synchronizedMap(HashMap)之间的区别

时间:2012-01-16 04:10:25

标签: java collections synchronization hashmap hashtable

据我所知,java.util.Hashtable同步java.util.Map接口中的每个方法,而Collections.synchronizedMap(hash_map)返回一个包装器对象,其中包含将调用委托给实际hash_map的同步方法(如果我错了,请纠正我。)

我有两个问题:

  1. 同步每个方法和拥有包装类有什么不同?选择其中一种的方案是什么?

  2. 当我们Collections.synchronizedMap(hash_table)时会发生什么?这是否等于使用普通java.util.Hashtable

6 个答案:

答案 0 :(得分:58)

我在两个类的实现中可以找到的另一个区别如下:

Hashtable类的所有方法都已同步,即锁定是在方法级别完成的,因此可以说Hashtable对象上的互斥锁总是 this )级别。

•方法Collections.synchronizedMap(Map)返回SynchronizedMap的实例,它是Collections类的内部类。该类的所有方法都在Synchronized块中,并带有互斥锁。不同之处在于互斥体。内部类SynchronizedMap有两个构造函数,一个仅将Map作为参数,另一个以MapObject(互斥)作为参数。默认情况下,如果使用仅传递Map的第一个构造函数, this 将用作互斥锁。但是,允许开发人员将另一个互斥对象作为第二个参数传递,Map方法上的锁仅限于Object,因此限制性比Hashtable更小。< / p>

•因此,Hashtable使用方法级同步,但Collections.synchronizedMap(Map)为开发人员提供了使用Synchronized阻止提供的互斥锁的灵活性。

答案 1 :(得分:14)

以下是我从一些(希望是正确的)研究得到的答案:

  1. 两者都提供相同程度的同步。如果您要通过Collections.synchronized包装Hashtable,那么您将具有相同的度数,但具有另一个冗余层,同步。

  2. HashtableCollections.synchronizedMap(HashMap)之间的主要区别在API级别更多。由于Hashtable是Java遗留代码的一部分,因此您将看到Hashtable API已得到增强,可实现Map接口,从而成为Java集合框架的一部分。这意味着,如果您要将Hashtable包裹到Collections.synchronizedMap(),则包装的Hashtable的API将仅限于Map API。因此,如果Hashtable的API包含在您对行为的定义中,那么它显然会被更改/限制。

答案 2 :(得分:4)

  

要出现在Java类中的第一个关联集合类   库是Hashtable,它是JDK 1.0的一部分。 Hashtable提供   一个易于使用,线程安全,关联的地图功能,它是   当然方便。然而,线程安全是有代价的 -   Hashtable的所有方法都是同步的。那个时候,无条件的   同步具有可测量的性能成本。接班人   Hashtable,HashMap,作为集合的一部分出现   JDK 1.2中的框架,通过提供一个来解决线程安全问题   非同步基类和同步包装器,   Collections.synchronizedMap。从中分离基本功能   线程安全Collections.synchronizedMap允许需要的用户   拥有它的同步,但不需要它的用户没有   支付它。

     

Hashtable和Hashtable采用的简单方法   synchronizedMap - 同步Hashtable上的每个方法或   synchronized Map包装器对象 - 有两个主要缺陷。它   是可伸缩性的障碍,因为只有一个线程可以访问   一次哈希表。与此同时,它还不够   在许多常见的复合操作中提供真正的线程安全性   仍然需要额外的同步。虽然操作简单如此   因为get()和put()可以安全地完成而无需额外的   同步,有几个常见的操作序列,   例如迭代或put-if-absent,它仍然需要外部   同步以避免数据争用。

以下链接是来源,有更多信息:Concurrent Collections Classes

答案 3 :(得分:3)

差异并非都在明显的API级别,并且在实现级别存在许多细微之处。例如,Hashtable没有运动HashMap高级重新计算所提供的密钥&#39;减少哈希冲突的哈希码。另一方面,Hashtable#hashCode()避免了自引用哈希表的无限递归,以允许某些带有自引用哈希表的1.1版applet工作&#34;。

但是,一般情况下,除了基本正确性和向后兼容性之外,不应指望Hashtable接受任何进一步的改进或改进。它被认为是Java过去的遗留物。

答案 4 :(得分:2)

要注意的另一个不同点是 HashTable 不允许空键或值,而 HashMap 允许一个空键和任意数量的空值。由于 synchronizedMap 是HashMap的包装器,因此它对null键和值的行为与HashMap相同。

答案 5 :(得分:1)

存在明显(或明显错误)的风险并不是

的区别
  

同步包装器添加自动同步   (线程安全)到任意集合

http://docs.oracle.com/javase/tutorial/collections/implementations/wrapper.html并继续说

  

以这种方式创建的集合与线程安全一样   通常是同步的集合,例如Vector。

您可能希望看到此线程有关HashMaps和并发的问题 - Hashmap concurrency issue(或者您可能已经非常了解它们)。一个很好的例子是:

  

HashMap不会满足您描述的条件。以来   更新地图的过程不是原子的,您可能会遇到地图   处于无效状态。多次写入可能会使其损坏   州。 ConcurrentHashMap(1.5或更高版本)可以满足您的需求。

https://stackoverflow.com/a/1003071/201648

我想在“我什么时候应该使用它”方面,我倾向于使用需要并发的同步集合,否则你可能会为自己创造更多的工作(见下文)。

在改变行为方面

  

如果使用显式迭代器,则必须调用迭代器方法   来自同步块内。不遵循这个建议可能会   导致不确定行为

在提供的(Oracle)链接上使用同步会产生更多后果。