单线程应用程序中的Hashtable vs HashMap性能

时间:2011-07-01 20:47:20

标签: java data-structures

我知道Hashtable已同步,因此可以安全地在多线程应用中使用,而HashMap则不然。

我想知道在单个线程应用程序中这两者之间是否存在任何性能差异。

(或者,何时使用其中一个?)

7 个答案:

答案 0 :(得分:4)

如果需要线程安全集合,可以将ConcurrentHashMap或Collections.synchronizedMap()与LinkedHashMap或HashMap一起使用。如果您不需要线程安全集合,则可以仅使用最后两个。 Hashtable已经过复古以支持Map with generics,但它也带有很多遗留方法,可以做同样的事情或者同样的事情。

可以使用Hashtable,但是恕我直言,使用后来开发的许多其他选项之一将是一个更清洁的解决方案。如果你有一个需要Hashtable的库,那么你需要使用它,否则我会使用一个满足你需要的类,遵循最少的遗留方法的最佳实践。

每次通话的性能差异可能约为0.5 us。这可能是也可能不重要。

但是,如果您不需要类型是线程安全的,则没有充分的理由使用同步版本。如果你需要一种线程安全的类型,你就不能使用一种没有线程安全保护的类型。

答案 1 :(得分:2)

在评论中提及@svick提到的内容。如果您正在讨论Java SDK中包含的HashtableHashMap,那么肯定存在性能差异,因为HashMap不必使用synchronized块,有开销。

根据pst的要求,这里有一些关于synchronized performance的阅读,这里有一些更新的,regarding Java 1.4 vs Java 6在一台机器上。

答案 2 :(得分:1)

由于Java 7声称可以进行转义分析,并在某些情况下删除无竞争同步,因此我给了它一个测试

public static void main(String[] args)
{
    for(int i=0; i<100; i++)
    {
        System.out.println("-------------------");
        testS();
    }
}
static int N = 100_000_000;
static void testS()
{
    Object o = new Object();
    long t0 = System.nanoTime();
    for(int i=0; i<N; i++)
        synchronized (o){}
    long t = System.nanoTime() - t0;
    System.out.printf("time: %,d%n", t);
}

我想不出一个简单的逃逸分析例子。但是,显然Java 7并没有在我的测试中优化同步;每个synchronized (o){}消耗一些时间。

令人惊讶的是,它只消耗大约1个CPU周期,这太快了。它应包含至少两个比较和设置指令;访问L1缓存通常需要10个周期。显然,正在进行一些硬件优化。

这是一个紧凑的循环,而不是真正的应用程序。一般来说讨论真正的应用程序太困难了;即使是具体的应用也很难分析。那么我们可能应该选择HashMap,如果可能的话,至少在任何情况下都不会比Hashtable慢,就我们所知。

答案 3 :(得分:1)

差异

  • HashMap允许空值,而Hashtable不允许。
  • 哈希表已同步,而哈希表未同步。 (但是如果未修改,它仍然可以用于多线程读取,例如-在启动时初始化一次,并且仅从其中读取某些静态缓存)

性能

这里有一些单线程测试可以进行比较。 5次100磨合操作尝试(第1次尝试可能被视为热身)的投掷是100%的碰撞,获得的是50%的命中。

if
  • 单线程
    HashMap通常更快。它的获取速度比哈希表快2倍。但是,其吞吐速度要慢25%
  • 同时使用
    如果不需要空值,则为Hashtable;如果需要空值,则为Collections.synchronizedMap(new HashMap <>())。请注意,Synchronized-HashMap比Hashtable慢(放慢2倍,慢50%)

用于测试的代码作为JUnit:

1 HashMap put/get -->   419.80  /   354.09  ms
2 HashMap put/get -->   983.02  /   305.54  ms
3 HashMap put/get -->   976.26  /   358.72  ms
4 HashMap put/get -->   989.04  /   375.18  ms
5 HashMap put/get -->   974.13  /   360.73  ms

1 Hashtable put/get -->   776.97  /   708.39  ms
2 Hashtable put/get -->   776.26  /   736.23  ms
3 Hashtable put/get -->   794.01  /   740.07  ms
4 Hashtable put/get -->   784.23  /   734.40  ms
5 Hashtable put/get -->   782.45  /   729.48  ms

1 Synced-HashMap put/get -->  1523.61  /  1215.63  ms
2 Synced-HashMap put/get -->  1491.59  /  1090.83  ms
3 Synced-HashMap put/get -->  1442.67  /  1095.62  ms
4 Synced-HashMap put/get -->  1439.19  /  1082.57  ms
5 Synced-HashMap put/get -->  1450.04  /  1101.53  ms

答案 4 :(得分:0)

是。这是默认情况下HashMap未被同步的(其中一个)点(使用synchronizedMap()使其同步;虽然请注意,根据您的使用情况,仅仅简单的同步可能不足以保持您可能想要的所有操作的完整性做)。

答案 5 :(得分:0)

如果你甚至可以测量真实世界测试中的差异,我会感到很惊讶。如果你可以测量数以万计的操作,但是你不会做数以万计,你将很难达到第一百万。

答案 6 :(得分:0)

如果Hashtable与HashMap上没有数字,但几年前I compared Vector with ArrayList存在类似问题。