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

时间:2022-03-26 16:48:33

As far as I know, java.util.Hashtable synchronizes each and every method in the java.util.Map interface, while Collections.synchronizedMap(hash_map) returns a wrapper object containing synchronized methods delegating calls to the actual hash_map (correct me if I am wrong).

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

I have two questions :

我有两个问题:

  1. What difference does it make to synchronize each and every method and to have a wrapper class? What are the scenarios to choose one over the other?

    它与同步每个方法和包装类有什么区别?有哪些方案可以选择其中一种?

  2. What happens when we do Collections.synchronizedMap(hash_table)? Will this be equal to simply using a normal java.util.Hashtable?

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

6 个解决方案

#1


14  

Here are the answers I've gotten from a bit of (hopefully correct) research:

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

  1. Both provide the same degree of synchronization. If you were to wrap Hashtable through Collections.synchronized you would have the same degree, but with another redundant layer, of synchronization.

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

  2. The main difference between Hashtable and Collections.synchronizedMap(HashMap) exist more at the API level. Because Hashtable is part of Java's legacy code, you'll see that the Hashtable API is enhanced to implement the Map interface, to become part of Java's collections framework. This means that if you were to wrap Hashtable through Collections.synchronizedMap(), the API of the wrapped Hashtable would become limited to the Map API. So if the API of Hashtable is encompassed in your definition of behavior, then it is obviously altered/limited.

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

#2


53  

One more difference that I can find at the implementation of both the classes is as follows:

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

• The Hashtable class has all its methods synchronized i.e. the locking is done at the method level and hence one can say that the mutex is always at the Hashtable object (this) level.

•Hashtable类使其所有方法同步,即锁定在方法级别完成,因此可以说互斥锁始终处于Hashtable对象(this)级别。

• The method Collections.synchronizedMap(Map) returns an instance of SynchronizedMap which is an inner class to the Collections class. This class has all its methods in a Synchronized block with a mutex. The difference lies in the mutex here. The inner class SynchronizedMap has two constructors, one which takes only Map as an argument and another which takes a Map and an Object (mutex) as an argument. By default if one uses the first constructor of passing only a Map, this is used as a mutex. Though, the developer is allowed to pass another object of mutex as a second argument by which the lock on the Map methods would be only on that Object and hence less restrictive than Hashtable.

•方法Collections.synchronizedMap(Map)返回SynchronizedMap的实例,它是Collections类的内部类。此类在具有互斥锁的同步块中具有其所有方法。不同之处在于互斥体。内部类SynchronizedMap有两个构造函数,一个只接受Map作为参数,另一个接受Map和对象(互斥)作为参数。默认情况下,如果使用仅传递Map的第一个构造函数,则将其用作互斥锁。但是,允许开发人员传递另一个互斥对象作为第二个参数,通过该对象,Map方法上的锁定仅在该对象上,因此比Hashtable更少限制。

• Hence, Hashtable uses method level synchronization but Collections.synchronizedMap(Map) provides a flexibility to developer lock on provided mutex with Synchronized block.

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

#3


4  

The first associative collection class to appear in the Java class library was Hashtable, which was part of JDK 1.0. Hashtable provided an easy-to-use, thread-safe, associative map capability, and it was certainly convenient. However, the thread-safety came at a price -- all methods of Hashtable were synchronized. At that time, uncontended synchronization had a measurable performance cost. The successor to Hashtable, HashMap, which appeared as part of the Collections framework in JDK 1.2, addressed thread-safety by providing an unsynchronized base class and a synchronized wrapper, Collections.synchronizedMap. Separating the base functionality from the thread-safety Collections.synchronizedMap allowed users who needed synchronization to have it, but users who didn't need it didn't have to pay for it.

出现在Java类库中的第一个关联集合类是Hashtable,它是JDK 1.0的一部分。 Hashtable提供了一个易于使用,线程安全的关联映射功能,它当然很方便。然而,线程安全是有代价的 - 所有Hashtable方法都是同步的。那时,无竞争同步具有可测量的性能成本。 HashMap的后继者HashMap作为JDK 1.2中Collections框架的一部分出现,它通过提供一个不同步的基类和一个同步包装器Collections.synchronizedMap来解决线程安全问题。将基本功能与线程安全性Collections.synchronizedMap分离,允许需要同步的用户拥有它,但不需要它的用户不必为此付费。

The simple approach to synchronization taken by both Hashtable and synchronizedMap -- synchronizing each method on the Hashtable or the synchronized Map wrapper object -- has two principal deficiencies. It is an impediment to scalability, because only one thread can access the hash table at a time. At the same time, it is insufficient to provide true thread safety, in that many common compound operations still require additional synchronization. While simple operations such as get() and put() can complete safely without additional synchronization, there are several common sequences of operations, such as iteration or put-if-absent, which still require external synchronization to avoid data races.

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

The following link is the source and has more information: Concurrent Collections Classes

以下链接是源代码,包含更多信息:并发集合类

#4


3  

The difference is not all at the obvious API level and there are many subtleties at the implementation level. For example, Hashtable doesn't sport HashMap's advanced recalculation of supplied keys' hashcodes that reduces hash collisions. On the other hand, Hashtable#hashCode() avoids infinite recursion for self-referential hashtables to allow "certain 1.1-era applets with self-referential hash tables to work".

不同之处在于明显的API级别,并且在实现级别上存在许多细微之处。例如,Hashtable不会通过HashMap对提供的密钥的哈希码进行高级重新计算,从而减少哈希冲突。另一方面,Hashtable #hashCode()避免了自引用哈希表的无限递归,以允许“具有自引用哈希表的某些1.1时代的applet工作”。

In general, though, one shouldn't count on Hashtable receiving any further improvements or refinements beyond basic correctness and backward compatibility. It is considered a relic from the deep Java past.

但是,一般而言,不应指望Hashtable接收除基本正确性和向后兼容性之外的任何进一步改进或改进。它被认为是Java深层历史遗留下来的遗物。

#5


1  

At the risk of stating the obvious (or being plain wrong) isn't the difference that

陈述明显(或明显错误)的风险并非如此

The synchronization wrappers add automatic synchronization (thread-safety) to an arbitrary collection

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

http://docs.oracle.com/javase/tutorial/collections/implementations/wrapper.html and continues to say

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

A collection created in this fashion is every bit as thread-safe as a normally synchronized collection, such as a Vector.

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

You may like to see this thread for issues regarding HashMaps and concurrency - Hashmap concurrency issue (or you are possibly very much aware of them already). A good example is:

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

The conditions you describe will not be satisfied by HashMap. Since the process of updating a map is not atomic you may encounter the map in an invalid state. Multiple writes might leave it in a corrupted state. ConcurrentHashMap (1.5 or later) does what you want.

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

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

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

I guess in terms of "when should I use this" I would tend to use the syncronised collection where concurrency is required, otherwise you may be creating more work for yourself (see below).

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

In terms of altering the behavior

在改变行为方面

If an explicit iterator is used, the iterator method must be called from within the synchronized block. Failure to follow this advice may result in nondeterministic behavior

如果使用显式迭代器,则必须从synchronized块中调用迭代器方法。不遵循此建议可能会导致不确定的行为

There are more consequences of using synchronization given at the (Oracle) link provided.

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

#6


0  

Another point of difference to note is that HashTable does not allow null keys or values whereas HashMap allows one null key and any number of null values. Since synchronizedMap is wrapper over HashMap, its behavior with respect to null keys and values is same as HashMap.

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

#1


14  

Here are the answers I've gotten from a bit of (hopefully correct) research:

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

  1. Both provide the same degree of synchronization. If you were to wrap Hashtable through Collections.synchronized you would have the same degree, but with another redundant layer, of synchronization.

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

  2. The main difference between Hashtable and Collections.synchronizedMap(HashMap) exist more at the API level. Because Hashtable is part of Java's legacy code, you'll see that the Hashtable API is enhanced to implement the Map interface, to become part of Java's collections framework. This means that if you were to wrap Hashtable through Collections.synchronizedMap(), the API of the wrapped Hashtable would become limited to the Map API. So if the API of Hashtable is encompassed in your definition of behavior, then it is obviously altered/limited.

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

#2


53  

One more difference that I can find at the implementation of both the classes is as follows:

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

• The Hashtable class has all its methods synchronized i.e. the locking is done at the method level and hence one can say that the mutex is always at the Hashtable object (this) level.

•Hashtable类使其所有方法同步,即锁定在方法级别完成,因此可以说互斥锁始终处于Hashtable对象(this)级别。

• The method Collections.synchronizedMap(Map) returns an instance of SynchronizedMap which is an inner class to the Collections class. This class has all its methods in a Synchronized block with a mutex. The difference lies in the mutex here. The inner class SynchronizedMap has two constructors, one which takes only Map as an argument and another which takes a Map and an Object (mutex) as an argument. By default if one uses the first constructor of passing only a Map, this is used as a mutex. Though, the developer is allowed to pass another object of mutex as a second argument by which the lock on the Map methods would be only on that Object and hence less restrictive than Hashtable.

•方法Collections.synchronizedMap(Map)返回SynchronizedMap的实例,它是Collections类的内部类。此类在具有互斥锁的同步块中具有其所有方法。不同之处在于互斥体。内部类SynchronizedMap有两个构造函数,一个只接受Map作为参数,另一个接受Map和对象(互斥)作为参数。默认情况下,如果使用仅传递Map的第一个构造函数,则将其用作互斥锁。但是,允许开发人员传递另一个互斥对象作为第二个参数,通过该对象,Map方法上的锁定仅在该对象上,因此比Hashtable更少限制。

• Hence, Hashtable uses method level synchronization but Collections.synchronizedMap(Map) provides a flexibility to developer lock on provided mutex with Synchronized block.

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

#3


4  

The first associative collection class to appear in the Java class library was Hashtable, which was part of JDK 1.0. Hashtable provided an easy-to-use, thread-safe, associative map capability, and it was certainly convenient. However, the thread-safety came at a price -- all methods of Hashtable were synchronized. At that time, uncontended synchronization had a measurable performance cost. The successor to Hashtable, HashMap, which appeared as part of the Collections framework in JDK 1.2, addressed thread-safety by providing an unsynchronized base class and a synchronized wrapper, Collections.synchronizedMap. Separating the base functionality from the thread-safety Collections.synchronizedMap allowed users who needed synchronization to have it, but users who didn't need it didn't have to pay for it.

出现在Java类库中的第一个关联集合类是Hashtable,它是JDK 1.0的一部分。 Hashtable提供了一个易于使用,线程安全的关联映射功能,它当然很方便。然而,线程安全是有代价的 - 所有Hashtable方法都是同步的。那时,无竞争同步具有可测量的性能成本。 HashMap的后继者HashMap作为JDK 1.2中Collections框架的一部分出现,它通过提供一个不同步的基类和一个同步包装器Collections.synchronizedMap来解决线程安全问题。将基本功能与线程安全性Collections.synchronizedMap分离,允许需要同步的用户拥有它,但不需要它的用户不必为此付费。

The simple approach to synchronization taken by both Hashtable and synchronizedMap -- synchronizing each method on the Hashtable or the synchronized Map wrapper object -- has two principal deficiencies. It is an impediment to scalability, because only one thread can access the hash table at a time. At the same time, it is insufficient to provide true thread safety, in that many common compound operations still require additional synchronization. While simple operations such as get() and put() can complete safely without additional synchronization, there are several common sequences of operations, such as iteration or put-if-absent, which still require external synchronization to avoid data races.

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

The following link is the source and has more information: Concurrent Collections Classes

以下链接是源代码,包含更多信息:并发集合类

#4


3  

The difference is not all at the obvious API level and there are many subtleties at the implementation level. For example, Hashtable doesn't sport HashMap's advanced recalculation of supplied keys' hashcodes that reduces hash collisions. On the other hand, Hashtable#hashCode() avoids infinite recursion for self-referential hashtables to allow "certain 1.1-era applets with self-referential hash tables to work".

不同之处在于明显的API级别,并且在实现级别上存在许多细微之处。例如,Hashtable不会通过HashMap对提供的密钥的哈希码进行高级重新计算,从而减少哈希冲突。另一方面,Hashtable #hashCode()避免了自引用哈希表的无限递归,以允许“具有自引用哈希表的某些1.1时代的applet工作”。

In general, though, one shouldn't count on Hashtable receiving any further improvements or refinements beyond basic correctness and backward compatibility. It is considered a relic from the deep Java past.

但是,一般而言,不应指望Hashtable接收除基本正确性和向后兼容性之外的任何进一步改进或改进。它被认为是Java深层历史遗留下来的遗物。

#5


1  

At the risk of stating the obvious (or being plain wrong) isn't the difference that

陈述明显(或明显错误)的风险并非如此

The synchronization wrappers add automatic synchronization (thread-safety) to an arbitrary collection

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

http://docs.oracle.com/javase/tutorial/collections/implementations/wrapper.html and continues to say

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

A collection created in this fashion is every bit as thread-safe as a normally synchronized collection, such as a Vector.

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

You may like to see this thread for issues regarding HashMaps and concurrency - Hashmap concurrency issue (or you are possibly very much aware of them already). A good example is:

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

The conditions you describe will not be satisfied by HashMap. Since the process of updating a map is not atomic you may encounter the map in an invalid state. Multiple writes might leave it in a corrupted state. ConcurrentHashMap (1.5 or later) does what you want.

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

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

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

I guess in terms of "when should I use this" I would tend to use the syncronised collection where concurrency is required, otherwise you may be creating more work for yourself (see below).

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

In terms of altering the behavior

在改变行为方面

If an explicit iterator is used, the iterator method must be called from within the synchronized block. Failure to follow this advice may result in nondeterministic behavior

如果使用显式迭代器,则必须从synchronized块中调用迭代器方法。不遵循此建议可能会导致不确定的行为

There are more consequences of using synchronization given at the (Oracle) link provided.

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

#6


0  

Another point of difference to note is that HashTable does not allow null keys or values whereas HashMap allows one null key and any number of null values. Since synchronizedMap is wrapper over HashMap, its behavior with respect to null keys and values is same as HashMap.

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