繁体   English   中英

Java中同步Hashmap vs ConcurrentHashMap的性能评估

[英]Performance evaluation of synchronized Hashmap vs ConcurrentHashMap in Java

我已经根据这个https://dzone.com/articles/java-7-hashmap-vs编写了一个小测试来测试哪种方法性能更好

threadSafeMap2 = new HashMap<String, Integer>(2);
threadSafeMap2 = Collections.synchronizedMap(threadSafeMap2);

或者

threadSafeMap3 = new ConcurrentHashMap<String, Integer>(2)

这是我的junit测试:

package com.bm.framework.concurrent;

import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

import org.junit.Test;

class WorkerThread implements Runnable 
{

    static final int WORKER_ITERATION_COUNT = 500000;
    private Map<String, Integer> map = null;

    public WorkerThread(Map<String, Integer> assignedMap) 
    {

          this.map = assignedMap;
    }

    @Override
    public void run() 
    {
          for (int i=0; i < WORKER_ITERATION_COUNT; i++) 
          {

                 // Return 2 integers between 1-1000000 inclusive

                 Integer newInteger1 = (int) Math.ceil(Math.random() * 1000000);

                 Integer newInteger2 = (int) Math.ceil(Math.random() * 1000000);                    

                 // 1. Attempt to retrieve a random Integer element

                 Integer retrievedInteger = map.get(String.valueOf(newInteger1));

                 // 2. Attempt to insert a random Integer element

                 map.put(String.valueOf(newInteger2), newInteger2);                
          }
    }
}



public class BmfThreadPoolTest 
{
    private static final int NB_THREADS = 3;
    private static final int NB_TEST_ITERATIONS = 50;


    private static Map<String, Integer> nonThreadSafeMap = null;
    private static Map<String, Integer> threadSafeMap2 = null;
    private static Map<String, Integer> threadSafeMap3 = null;


    @Test
    public void testMapPerformance() throws InterruptedException 
    {
        // this is a test between two styles we see
        // one is to use Collections.synchronizedMap()
        // and the other one is to use directly ConcurrentHashMap which 
        // one is faster?
        // Plain old HashMap (since JDK 1.2)
        nonThreadSafeMap = new HashMap<String, Integer>(2);

        // Fully synchronized HashMap
        threadSafeMap2 = new HashMap<String, Integer>(2);
        threadSafeMap2 = Collections.synchronizedMap(threadSafeMap2);

        // ConcurrentHashMap (since JDK 1.5)
        threadSafeMap3 = new ConcurrentHashMap<String, Integer>(2);
        System.out.println("ConcurrentHashMap");
        beginTest(threadSafeMap3);
        // the second one is always performing poor no matter whether it is hashmap or concurrenthashmap why????
        System.out.println("Collections.synchronizedMap()");
        beginTest(threadSafeMap2);

    }

    private void beginTest(final Map<String, Integer> assignedMapForTest)
    {
        for (int i=0; i<NB_TEST_ITERATIONS; i++) 
        {
            long timeBefore = System.currentTimeMillis();
            long timeAfter = 0;

            Float totalProcessingTime = null;

            ExecutorService executor = Executors.newFixedThreadPool(NB_THREADS);

            for (int j = 0; j < NB_THREADS; j++) 
            {

                   /** Assign the Map at your convenience **/

                   Runnable worker = new WorkerThread(assignedMapForTest);
                   executor.execute(worker);              

            }

            // This will make the executor accept no new threads

            // and finish all existing threads in the queue

            executor.shutdown();

            // Wait until all threads are finish

            while (!executor.isTerminated()) 
            {

            }

            timeAfter = System.currentTimeMillis();

            totalProcessingTime = new Float( (float) (timeAfter - timeBefore) / (float) 1000);

            System.out.println("All threads completed in "+totalProcessingTime+" seconds");
        }
    }   
}

问题是在两个 beginTest() 调用中,第二个总是执行不好,即,如果我这样运行

beginTest(threadSafeMap3);
beginTest(threadSafeMap2); 

最后一个需要更长的时间才能完成,这表明 ConcurrentHashMap 更快。 再次,如果我像这样交换订单

beginTest(threadSafeMap2);
beginTest(threadSafeMap3); 

最后一个需要更长的时间才能完成,这表明 ConcurrentHashMap 速度较慢。 为什么根据测试中使用地图的顺序,我会得到相互矛盾的结果?

如果我注释掉其中之一并在两次单独的运行中运行测试(一次用于同步哈希映射,另一次用于 ConcurrentHashMap),那么我总是以 ConcurrentHashMap 作为获胜者获得一致的结果。

  1. 您应该使用您的实际使用模式对此进行测试:与程序的其余部分相比,地图的开销很可能可以忽略不计 - 即使不是,地图的使用方式也可能很重要。 因此,测量整个应用程序通常比对单个组件进行微基准测试更好。
  2. 在微基准测试中,您应该对被测代码进行预热,因此在计时阶段不会首先采用代码路径,以确保您不会对解释代码或即时编译本身进行基准测试
  3. 您应该将测试分成不同的方法。 这将允许垃圾收集器释放第一次测试运行所消耗的内存,因此两个测试都以相同的堆大小和垃圾收集开销运行。 (在您的代码中,JVM 可能没有意识到一旦第二个测试开始就不再使用第一个映射......)

背景阅读: 如何用Java编写正确的微基准测试?

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM