如何实现线程的HashMap以及性能对比
2016-12-24 11:52
387 查看
对于线程是否是安全的问题,一般是不会用到的,因为在开发中通用的是单线程倒是不用担心线程安全问题。
但是对于要进行高并发的开发,线程安全就必不可少了,这也是面试的拦路虎,在此总结一下前人的经验,进行线程安全的总结,如有不足的地方请指出交流。
借鉴别人的测试代码并完善一下:
测试结果:
由打印结果发现 HashMap居然能够累加到500w.难道HashMap也能线程安全吗?
================================== map securicty test start ==================================
Test started for: class java.util.HashMap
value is :500000
value is :1000000
1-1000000 entried added/retrieved in 57 ms
value is :1500000
value is :2000000
2-1000000 entried added/retrieved in 51 ms
value is :2500000
value is :3000000
3-1000000 entried added/retrieved in 38 ms
value is :3500000
value is :4000000
4-1000000 entried added/retrieved in 35 ms
value is :4500000
value is :5000000
5-1000000 entried added/retrieved in 35 ms
For class java.util.HashMap the average time is 43 ms
Test started for: class java.util.Hashtable
value is :500000
value is :1000000
1-1000000 entried added/retrieved in 97 ms
value is :1500000
value is :2000000
2-1000000 entried added/retrieved in 66 ms
value is :2500000
value is :3000000
3-1000000 entried added/retrieved in 67 ms
value is :3500000
value is :4000000
4-1000000 entried added/retrieved in 65 ms
value is :4500000
value is :5000000
5-1000000 entried added/retrieved in 61 ms
For class java.util.Hashtable the average time is 71 ms
Test started for: class java.util.Collections$SynchronizedMap
value is :500000
value is :1000000
1-1000000 entried added/retrieved in 111 ms
value is :1500000
value is :2000000
2-1000000 entried added/retrieved in 90 ms
value is :2500000
value is :3000000
3-1000000 entried added/retrieved in 92 ms
value is :3500000
value is :4000000
4-1000000 entried added/retrieved in 94 ms
value is :4500000
value is :5000000
5-1000000 entried added/retrieved in 98 ms
For class java.util.Collections$SynchronizedMap the average time is 97 ms
Test started for: class java.util.concurrent.ConcurrentHashMap
value is :500000
value is :1000000
1-1000000 entried added/retrieved in 40 ms
value is :1500000
value is :2000000
2-1000000 entried added/retrieved in 35 ms
value is :2500000
value is :3000000
3-1000000 entried added/retrieved in 32 ms
value is :3500000
value is :4000000
4-1000000 entried added/retrieved in 34 ms
value is :4500000
value is :5000000
5-1000000 entried added/retrieved in 33 ms
For class java.util.concurrent.ConcurrentHashMap the average time is 34 ms
================================== map securicty test end ==================================
带着疑问再次进行单独测试:
Test started for: class java.util.HashMap
value is :500000
1-1000000 entried added/retrieved in 51 ms
value is :1000000
value is :1500000
2-1000000 entried added/retrieved in 40 ms
value is :2000000
value is :2500000
3-1000000 entried added/retrieved in 31 ms
value is :3000000
value is :3500000
4-1000000 entried added/retrieved in 30 ms
value is :4000000
value is :4500000
5-1000000 entried added/retrieved in 30 ms
For class java.util.HashMap the average time is 36 ms
发现这次就没有能够达到线程安全。
所以线程安全的策略有三种,而且要和atomic结合操作才能实现。
效率测试如下:
HashMap的效率最高,如果不考虑线程的问题(单线程使用的时候),HashMap是首选。
其次是ConcurrentHashMap,Collections$SynchronizedMap,Hashtable 。
一般情况下ConcurrentHashMap效率能够达到Collections$SynchronizedMap或者Hashtable 的两倍,
================================== map Efficience test start ==================================
Test started for: class java.util.HashMap
2500K entried added/retrieved in 58 ms
2500K entried added/retrieved in 49 ms
2500K entried added/retrieved in 26 ms
2500K entried added/retrieved in 27 ms
2500K entried added/retrieved in 28 ms
For class java.util.HashMap the average time is 37 ms
Test started for: class java.util.Hashtable
2500K entried added/retrieved in 113 ms
2500K entried added/retrieved in 76 ms
2500K entried added/retrieved in 72 ms
2500K entried added/retrieved in 75 ms
2500K entried added/retrieved in 74 ms
For class java.util.Hashtable the average time is 82 ms
Test started for: class java.util.Collections$SynchronizedMap
2500K entried added/retrieved in 100 ms
2500K entried added/retrieved in 87 ms
2500K entried added/retrieved in 88 ms
2500K entried added/retrieved in 84 ms
2500K entried added/retrieved in 87 ms
For class java.util.Collections$SynchronizedMap the average time is 89 ms
Test started for: class java.util.concurrent.ConcurrentHashMap
2500K entried added/retrieved in 63 ms
2500K entried added/retrieved in 58 ms
2500K entried added/retrieved in 58 ms
2500K entried added/retrieved in 57 ms
2500K entried added/retrieved in 60 ms
For class java.util.concurrent.ConcurrentHashMap the average time is 59 ms
================================== map Efficience test end ==================================
参考: http://blog.csdn.net/cnhk1225/article/details/52413201
但是对于要进行高并发的开发,线程安全就必不可少了,这也是面试的拦路虎,在此总结一下前人的经验,进行线程安全的总结,如有不足的地方请指出交流。
借鉴别人的测试代码并完善一下:
import java.util.Collections; import java.util.HashMap; import java.util.Hashtable; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicLong; public class CrunchifyConcurrentHashMapVsSynchronizedMap { public final static int THREAD_POOL_SIZE = 10; public final static int THREAD_LOOP_TIME = 100000; public final static String key = "wordcounts" ; public static Map<String, AtomicLong> crunchifyHashTableObject = null; public static Map<String, AtomicLong> crunchifySynchronizedMapObject = null; public static Map<String, AtomicLong> crunchifyConcurrentHashMapObject = null; public static Map<String, AtomicLong> crunchifyHashMapObject = null; public static void main(String[] args) throws InterruptedException { // 安全性测试 mapSecurictyTest(); //效率测试 mapEfficienceTest(); } private static void mapSecurictyTest() throws InterruptedException { // Test with HashMap Object crunchifyHashMapObject = new HashMap<>(); threadSecurityTest(crunchifyHashMapObject); // Test with Hashtable Object crunchifyHashTableObject = new Hashtable<>(); threadSecurityTest(crunchifyHashTableObject); // Test with synchronizedMap Object crunchifySynchronizedMapObject = Collections.synchronizedMap(new HashMap<String, AtomicLong>()); threadSecurityTest(crunchifySynchronizedMapObject); // Test with ConcurrentHashMap Object crunchifyConcurrentHashMapObject = new ConcurrentHashMap<>(); threadSecurityTest(crunchifyConcurrentHashMapObject); } private static void mapEfficienceTest() throws InterruptedException { // 效率最高 38ms Map<String, Integer> crunchifyHashMapObject = null; // For class java.util.Hashtable the average time is 82 ms Map<String, Integer> crunchifyHashTableObject = null; // For class java.util.Collections$SynchronizedMap the average time is 84 ms Map<String, Integer> crunchifySynchronizedMapObject = null; // For class java.util.concurrent.ConcurrentHashMap the average time is 58 ms Map<String, Integer> crunchifyConcurrentHashMapObject = null; // Test with HashMap Object crunchifyHashMapObject = new HashMap<>(); crunchifyPerformTest(crunchifyHashMapObject); // Test with Hashtable Object crunchifyHashTableObject = new Hashtable<>(); crunchifyPerformTest(crunchifyHashTableObject); // Test with synchronizedMap Object crunchifySynchronizedMapObject = Collections.synchronizedMap(new HashMap<String, Integer>()); crunchifyPerformTest(crunchifySynchronizedMapObject); // Test with ConcurrentHashMap Object crunchifyConcurrentHashMapObject = new ConcurrentHashMap<>(); crunchifyPerformTest(crunchifyConcurrentHashMapObject); } public static void threadSecurityTest( final Map<String, AtomicLong> map) throws InterruptedException { System.out.println("Test started for: " + map.getClass()); long averageTime = 0; for (int i = 0; i < 5; i++) { long startTime = System.nanoTime(); ExecutorService crunchifyExServer = Executors.newFixedThreadPool(THREAD_POOL_SIZE); for (int j = 0; j < THREAD_POOL_SIZE; j++) { crunchifyExServer.execute(new Runnable() { @Override public void run() { for (int i = 0; i < THREAD_LOOP_TIME; i++) { AtomicLong number = map.get(key); if (number == null) { AtomicLong newNumber = new AtomicLong(0); number = map.putIfAbsent(key, newNumber); if (number == null) { number = newNumber; } } long incrementValue = number.incrementAndGet(); if ((incrementValue )%500000==00) { System.out.println("value is :" +(incrementValue )); } } } }); } // Make sure executor stops crunchifyExServer.shutdown(); // Blocks until all tasks have completed execution after a shutdown request crunchifyExServer.awaitTermination(Long.MAX_VALUE, TimeUnit.DAYS); long entTime = System.nanoTime(); long totalTime = (entTime - startTime) / 1000000L; averageTime += totalTime; System.out.println( (i+1 )+"-"+THREAD_POOL_SIZE*THREAD_LOOP_TIME +" entried added/retrieved in " + totalTime + " ms"); } System.out.println("For " + map.getClass() + " the average time is " + averageTime / 5 + " ms\n"); } public static void crunchifyPerformTest( final Map<String, Integer> crunchifyThreads) throws InterruptedException { System.out.println("Test started for: " + crunchifyThreads.getClass()); long averageTime = 0; for (int i = 0; i < 5; i++) { long startTime = System.nanoTime(); ExecutorService crunchifyExServer = Executors.newFixedThreadPool(THREAD_POOL_SIZE); for (int j = 0; j < THREAD_POOL_SIZE; j++) { crunchifyExServer.execute(new Runnable() { @Override public void run() { for (int i = 0; i < THREAD_LOOP_TIME; i++) { // Retrieve value. We are not using it anywhere Integer crunchifyValue = crunchifyThreads.get(key); // Put value crunchifyThreads.put( key, new Integer(1)); } } }); } // Make sure executor stops crunchifyExServer.shutdown(); // Blocks until all tasks have completed execution after a shutdown request crunchifyExServer.awaitTermination(Long.MAX_VALUE, TimeUnit.DAYS); long entTime = System.nanoTime(); long totalTime = (entTime - startTime) / 1000000L; averageTime += totalTime; System.out.println("2500K entried added/retrieved in " + totalTime + " ms"); } System.out.println("For " + crunchifyThreads.getClass() + " the average time is " + averageTime / 5 + " ms\n"); } }
测试结果:
由打印结果发现 HashMap居然能够累加到500w.难道HashMap也能线程安全吗?
================================== map securicty test start ==================================
Test started for: class java.util.HashMap
value is :500000
value is :1000000
1-1000000 entried added/retrieved in 57 ms
value is :1500000
value is :2000000
2-1000000 entried added/retrieved in 51 ms
value is :2500000
value is :3000000
3-1000000 entried added/retrieved in 38 ms
value is :3500000
value is :4000000
4-1000000 entried added/retrieved in 35 ms
value is :4500000
value is :5000000
5-1000000 entried added/retrieved in 35 ms
For class java.util.HashMap the average time is 43 ms
Test started for: class java.util.Hashtable
value is :500000
value is :1000000
1-1000000 entried added/retrieved in 97 ms
value is :1500000
value is :2000000
2-1000000 entried added/retrieved in 66 ms
value is :2500000
value is :3000000
3-1000000 entried added/retrieved in 67 ms
value is :3500000
value is :4000000
4-1000000 entried added/retrieved in 65 ms
value is :4500000
value is :5000000
5-1000000 entried added/retrieved in 61 ms
For class java.util.Hashtable the average time is 71 ms
Test started for: class java.util.Collections$SynchronizedMap
value is :500000
value is :1000000
1-1000000 entried added/retrieved in 111 ms
value is :1500000
value is :2000000
2-1000000 entried added/retrieved in 90 ms
value is :2500000
value is :3000000
3-1000000 entried added/retrieved in 92 ms
value is :3500000
value is :4000000
4-1000000 entried added/retrieved in 94 ms
value is :4500000
value is :5000000
5-1000000 entried added/retrieved in 98 ms
For class java.util.Collections$SynchronizedMap the average time is 97 ms
Test started for: class java.util.concurrent.ConcurrentHashMap
value is :500000
value is :1000000
1-1000000 entried added/retrieved in 40 ms
value is :1500000
value is :2000000
2-1000000 entried added/retrieved in 35 ms
value is :2500000
value is :3000000
3-1000000 entried added/retrieved in 32 ms
value is :3500000
value is :4000000
4-1000000 entried added/retrieved in 34 ms
value is :4500000
value is :5000000
5-1000000 entried added/retrieved in 33 ms
For class java.util.concurrent.ConcurrentHashMap the average time is 34 ms
================================== map securicty test end ==================================
带着疑问再次进行单独测试:
Test started for: class java.util.HashMap
value is :500000
1-1000000 entried added/retrieved in 51 ms
value is :1000000
value is :1500000
2-1000000 entried added/retrieved in 40 ms
value is :2000000
value is :2500000
3-1000000 entried added/retrieved in 31 ms
value is :3000000
value is :3500000
4-1000000 entried added/retrieved in 30 ms
value is :4000000
value is :4500000
5-1000000 entried added/retrieved in 30 ms
For class java.util.HashMap the average time is 36 ms
发现这次就没有能够达到线程安全。
所以线程安全的策略有三种,而且要和atomic结合操作才能实现。
效率测试如下:
HashMap的效率最高,如果不考虑线程的问题(单线程使用的时候),HashMap是首选。
其次是ConcurrentHashMap,Collections$SynchronizedMap,Hashtable 。
一般情况下ConcurrentHashMap效率能够达到Collections$SynchronizedMap或者Hashtable 的两倍,
================================== map Efficience test start ==================================
Test started for: class java.util.HashMap
2500K entried added/retrieved in 58 ms
2500K entried added/retrieved in 49 ms
2500K entried added/retrieved in 26 ms
2500K entried added/retrieved in 27 ms
2500K entried added/retrieved in 28 ms
For class java.util.HashMap the average time is 37 ms
Test started for: class java.util.Hashtable
2500K entried added/retrieved in 113 ms
2500K entried added/retrieved in 76 ms
2500K entried added/retrieved in 72 ms
2500K entried added/retrieved in 75 ms
2500K entried added/retrieved in 74 ms
For class java.util.Hashtable the average time is 82 ms
Test started for: class java.util.Collections$SynchronizedMap
2500K entried added/retrieved in 100 ms
2500K entried added/retrieved in 87 ms
2500K entried added/retrieved in 88 ms
2500K entried added/retrieved in 84 ms
2500K entried added/retrieved in 87 ms
For class java.util.Collections$SynchronizedMap the average time is 89 ms
Test started for: class java.util.concurrent.ConcurrentHashMap
2500K entried added/retrieved in 63 ms
2500K entried added/retrieved in 58 ms
2500K entried added/retrieved in 58 ms
2500K entried added/retrieved in 57 ms
2500K entried added/retrieved in 60 ms
For class java.util.concurrent.ConcurrentHashMap the average time is 59 ms
================================== map Efficience test end ==================================
参考: http://blog.csdn.net/cnhk1225/article/details/52413201
相关文章推荐
- ArrayList、LinkedList和HashSet、TreeSet以及HashMap、TreeMap是如何实现存储的?
- 拿来主义:java中的线程安全与非线程安全,以及如何使用和实现
- WPF [调用线程无法访问此对象,因为另一个线程拥有该对象。] 解决方案以及如何实现字体颜色的渐变
- java基础—HashMap实现原理,如何保证HashMap的线程安全?
- WPF [调用线程无法访问此对象,因为另一个线程拥有该对象。] 解决方案以及如何实现字体颜色的渐变
- 牛客网Java刷题知识点之HashMap的实现原理、HashMap的存储结构、HashMap在JDK1.6、JDK1.7、JDK1.8之间的差异以及带来的性能影响
- Java设计模式(四):原型模式深拷贝的两种实现方式,以及和new对象的性能测试对比
- ArrayList、LinkedList和HashSet、TreeSet以及HashMap、TreeMap是如何实现存储的?
- ArrayList、LinkedList和HashSet、TreeSet以及HashMap、TreeMap是如何实现存储的?
- 什么是死锁?如何避免死锁? 以及实现线程死锁才程序
- ArrayList、LinkedList和HashSet、TreeSet以及HashMap、TreeMap是如何实现存储的?
- IIS VS Nginx 如何合理对比以及看待IIS和Nginx的性能
- HashMap多种遍历方式以及性能对比(JDK1.7)
- 牛客网Java刷题知识点之为什么HashMap不支持线程的同步,不是线程安全的?如何实现HashMap的同步?
- WPF [调用线程无法访问此对象,因为另一个线程拥有该对象。] 解决方案以及如何实现字体颜色的渐变
- 【转】WPF [调用线程无法访问此对象,因为另一个线程拥有该对象。] 解决方案以及如何实现字体颜色的渐变
- WPF [调用线程无法访问此对象,因为另一个线程拥有该对象。] 解决方案以及如何实现字体颜色的渐变
- 【数据结构】常见的排序方法的实现以及性能对比
- 线程和进程的区别?以及如何实现多线程
- asp小偷程序如何利用xmlhttp实现表单的提交以及cookies或session的发送