据我所知,java.util.Hashtable
同步java.util.Map
接口中的每个方法,而Collections.synchronizedMap(hash_map)
返回一个包装器对象,其中包含将调用委托给实际hash_map
的同步方法(如果我错了,请纠正我。)
我有两个问题:
同步每个方法和拥有包装类有什么不同?选择其中一种的方案是什么?
当我们Collections.synchronizedMap(hash_table)
时会发生什么?这是否等于使用普通java.util.Hashtable
?
答案 0 :(得分:58)
我在两个类的实现中可以找到的另一个区别如下:
•Hashtable
类的所有方法都已同步,即锁定是在方法级别完成的,因此可以说Hashtable
对象上的互斥锁总是 ( this
)级别。
•方法Collections.synchronizedMap(Map)
返回SynchronizedMap
的实例,它是Collections
类的内部类。该类的所有方法都在Synchronized
块中,并带有互斥锁。不同之处在于互斥体。内部类SynchronizedMap
有两个构造函数,一个仅将Map
作为参数,另一个以Map
和Object
(互斥)作为参数。默认情况下,如果使用仅传递Map
的第一个构造函数, this
将用作互斥锁。但是,允许开发人员将另一个互斥对象作为第二个参数传递,Map
方法上的锁仅限于Object
,因此限制性比Hashtable
更小。< / p>
•因此,Hashtable
使用方法级同步,但Collections.synchronizedMap(Map)
为开发人员提供了使用Synchronized
阻止提供的互斥锁的灵活性。
答案 1 :(得分:14)
以下是我从一些(希望是正确的)研究得到的答案:
两者都提供相同程度的同步。如果您要通过Collections.synchronized包装Hashtable
,那么您将具有相同的度数,但具有另一个冗余层,同步。
Hashtable
和Collections.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)链接上使用同步会产生更多后果。