8

我对这两个集合在多线程环境中的行为方式感到非常困惑。

哈希表是同步的,这意味着没有 2 个线程会同时更新它的值,对吧?

4

5 回答 5

14

查看ConcurrentHashMap的线程安全映射。

它们提供了 HashTable 的所有功能,性能非常接近 HashMap。

通过不使用映射范围的锁来获得性能,该集合默认维护一个包含 16 个锁的列表,每个锁用于锁定映射的单个存储桶。您甚至可以配置存储桶的数量 :) 调整这可以根据您的数据提高性能。

我不能推荐足够多的 Java Concurrency in Practice by Brian Goetz http://jcip.net/

每次阅读它,我仍然会学到一些新东西。

于 2009-09-01T11:01:20.270 回答
3

确切地说,HashTable 是同步的,这意味着在多线程环境中使用它是安全的(许多线程访问同一个 HashTable)如果两个线程尝试同时更新哈希表,其中一个必须等​​待另一个线程完成他的更新。

HashMap 不同步,因此速度更快,但在多线程环境中可能会出现问题。

于 2009-09-01T11:01:08.447 回答
3

还要注意 Hashtable 和Collections.synchronizedMap仅对单个操作是安全的。任何涉及多个键或需要原子检查的操作都不会如此,并且需要额外的客户端锁定。

例如,您不能在没有附加锁定的情况下编写以下任何方法:

  • 交换两个不同键的值:swapValues(Map, Object k1, Object k2)

  • 将参数附加到键处的值:appendToValue(Map, Object k1, String suffix)

是的,所有这些都包含在 JCIP 中 :-)

于 2009-09-01T11:13:15.440 回答
0

是的,所有方法都是原子完成的,但 values() 方法不是(请参阅文档)。

Paul 比我更快地向你推荐了 java.util.concurrent 包,它为多线程环境提供了非常精细的控制和数据结构。

于 2009-09-01T11:04:27.143 回答
0

哈希表是同步的,但它们是一个旧的实现,你几乎可以说它已被弃用。此外,它们不允许空键(也许也不是空值?不确定)。

一个问题是,虽然每个方法调用都是同步的,但大多数有趣的操作需要不止一个调用,因此您必须围绕多个调用进行同步。

通过调用 HashMap 可以获得类似级别的同步:

Map m = Collections.synchronizedMap(new HashMap());

它将映射包装在同步方法调用中。但这与 Hashtable 具有相同的并发缺点。

正如 Paul 所说,ConcurrentHashMaps 为线程安全映射提供了额外有用的原子更新方法。

于 2009-09-01T11:07:20.757 回答