Collections.synchronizedMap()、ConcurrentHashMap、Hashtable之间的区别
为什么要比较Hashtable、SynchronizedMap()、ConcurrentHashMap之间的关系?因为常用的HashMap是非线程安全的,不能满足在多线程高并发场景下的需求。
那么为什么说HashTable是线程不安全的?具体参阅关于java集合类HashMap的理解
如何线程安全的使用HashMap
了解了 HashMap 为什么线程不安全,那现在看看如何线程安全的使用 HashMap。这个无非就是以下三种方式:
- Hashtable
- ConcurrentHashMap
- Synchronized Map
Hashtable
那先说说Hashtable,Hashtable源码中是使用 synchronized
来保证线程安全的,比如下面的 get 方法和 put 方法:
public synchronized V get(Object key) {
// 省略实现
}
public synchronized V put(K key, V value) {
// 省略实现
}
所以当一个线程访问 HashTable 的同步方法时,其他线程如果也要访问同步方法,会被阻塞住。举个例子,当一个线程使用 put 方法时,另一个线程不但不可以使用 put 方法,连 get 方法都不可以,好霸道啊!!!so~~,效率很低,现在基本不会选择它了。
Collections.synchronizedMap()
看了一下源码,synchronizedMap()的实现还是很简单的。
// synchronizedMap方法
public static <K,V> Map<K,V> synchronizedMap(Map<K,V> m) {
return new SynchronizedMap<>(m);
}
// SynchronizedMap类
private static class SynchronizedMap<K,V>
implements Map<K,V>, Serializable {
private static final long serialVersionUID = 1978198479659022715L; private final Map<K,V> m; // Backing Map
final Object mutex; // Object on which to synchronize SynchronizedMap(Map<K,V> m) {
this.m = Objects.requireNonNull(m);
mutex = this;
} SynchronizedMap(Map<K,V> m, Object mutex) {
this.m = m;
this.mutex = mutex;
} public int size() {
synchronized (mutex) {return m.size();}
}
public boolean isEmpty() {
synchronized (mutex) {return m.isEmpty();}
}
public boolean containsKey(Object key) {
synchronized (mutex) {return m.containsKey(key);}
}
public boolean containsValue(Object value) {
synchronized (mutex) {return m.containsValue(value);}
}
public V get(Object key) {
synchronized (mutex) {return m.get(key);}
} public V put(K key, V value) {
synchronized (mutex) {return m.put(key, value);}
}
public V remove(Object key) {
synchronized (mutex) {return m.remove(key);}
}
// 省略其他方法
}
从源码中可以看出调用 synchronizedMap() 方法后会返回一个 SynchronizedMap 类的对象,而在 SynchronizedMap 类中使用了 synchronized 同步关键字来保证对 Map 的操作是线程安全的。
ConcurrentHashMap
Spring的源码中有很多使用ConcurrentHashMap的地方。具体参阅》》》》》》》》。需要注意的是,上面博客是基于 Java 7 的,和8有区别,在8中 CHM 摒弃了 Segment(锁段)的概念,而是启用了一种全新的方式实现,利用CAS算法。
下面通过一个具体例子看看Collections.synchronizedMap()和ConcurrentHashMap哪个性能更高。
public class Test { public final static int THREAD_POOL_SIZE = 5; public static Map<String, Integer> crunchifyHashTableObject = null;
public static Map<String, Integer> crunchifySynchronizedMapObject = null;
public static Map<String, Integer> crunchifyConcurrentHashMapObject = null; public static void main(String[] args) throws InterruptedException { // 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 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() {
@SuppressWarnings("unused")
@Override
public void run() { for (int i = 0; i < 500000; i++) {
Integer crunchifyRandomNumber = (int) Math.ceil(Math.random() * 550000); // Retrieve value. We are not using it anywhere
Integer crunchifyValue = crunchifyThreads.get(String.valueOf(crunchifyRandomNumber)); // Put value
crunchifyThreads.put(String.valueOf(crunchifyRandomNumber), crunchifyRandomNumber);
}
}
});
} // 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");
}
}
结果显示,ConcurrentHashMap性能是明显优于Hashtable和SynchronizedMap的,ConcurrentHashMap花费的时间比前两个的一半还少。
Collections.synchronizedMap()、ConcurrentHashMap、Hashtable之间的区别的更多相关文章
- ArrayList,Vector,HashMap,HashSet,HashTable之间的区别与联系
在编写java程序中,我们最常用的除了八种基本数据类型,String对象外还有一个集合类,在我们的的程序中到处充斥着集合类的身影!java中集合大家族的成员实在是太丰富了,有常用的ArrayList. ...
- LinkedList,ArrayList,Vector,HashMap,HashSet,HashTable之间的区别与联系
在编写java程序中,我们最常用的除了八种基本数据类型,String对象外还有一个集合类,在我们的的程序中到处充斥着集合类的身影!java中集合大家族的成员实在是太丰富了,有常用的ArrayList. ...
- HashTable、HashMap、ConcurrentHashMap、Collections.synchronizedMap()区别
Collections.synchronizedMap()和Hashtable一样,实现上在调用map所有方法时,都对整个map进行同步,而ConcurrentHashMap的实现却更加精细,它对Ha ...
- Collections.synchronizedMap()与ConcurrentHashMap的区别
前面文章提到Collections.synchronizedMap()与ConcurrentHashM两者都提供了线程同步的功能.那两者的区别在哪呢?我们们先来看到代码例子. 下面代码实现一个线 ...
- Collections.synchronizedMap()与ConcurrentHashMap区别
Collections.synchronizedMap()与ConcurrentHashMap主要区别是:Collections.synchronizedMap()和Hashtable一样,实现上在调 ...
- ConcurrentHashMap和 CopyOnWriteArrayList提供线程安全性和可伸缩性 以及 同步的集合类 Hashtable 和 Vector Collections.synchronizedMap 和 Collections.synchronizedList 区别缺点
ConcurrentHashMap和 CopyOnWriteArrayList提供线程安全性和可伸缩性 DougLea的 util.concurrent 包除了包含许多其他有用的并发构造块之外,还包含 ...
- 测试HashTable、Collections.synchronizedMap和ConcurrentHashMap的性能
对于map的并发操作有HashTable.Collections.synchronizedMap和ConcurrentHashMap三种,到底性能如何呢? 测试代码: package com. ...
- ConcurrentHashMap vs Collections.synchronizedMap()不同
之前项目中,有用到过Collections.synchronizedMap(),后面发现当并发数很多的时候,出现其他请求等待情况,因为synchronizedMap会锁住所有的资源,后面通过查阅资料, ...
- Hashtable,HashMap和ConcurrentHashMap的原理及区别
一.原理 Hashtable 底层数组+链表实现,无论key还是value都不能为null,线程安全,实现线程安全的方式是在修改数据时锁住整个HashTable,效率低,ConcurrentHashM ...
随机推荐
- 不错的东西: AutoMapper
详细信息可阅读原文:http://csharppulse.blogspot.in/2013/08/crud-operations-using-automapper-in-c_381.html 这东西可 ...
- 算法学习笔记(一)C++排序函数、映射技巧与字典树
1.头文件algorithm中有函数sort()用于排序,参数为:排序起始地址,排序结束地址,排序规则(返回bool型)例如,要将array[] = {5,7,1,2,9}升序排列,则使用: bool ...
- Struts2技术内幕 读书笔记一 框架的本质
本读书笔记系列,主要针对陆舟所著<<Struts2技术内幕 深入解析Strtus2架构设计与实现原理>>一书.笔记中所用的图片若无特殊说明,就都取自书中,特此声明. 什么是框架 ...
- Linux中find的使用(转)
本文转自:迷途花开 另一值得参考的是吴秦先生的博文linux中强大且常用命令:find.grep. find命令用于查找文件和目录,任何位于参数之前的字符串都将被视为欲查找的目录. find 可以指定 ...
- RTMPdump(libRTMP) 源代码分析 9: 接收消息(Message)(接收视音频数据)
===================================================== RTMPdump(libRTMP) 源代码分析系列文章: RTMPdump 源代码分析 1: ...
- C++语言之类class
在现实世界中,经常有属于同一类的对象.例如,你的自行车只是世界上很多自行车中的一辆.在面向对象软件中,也有很多共享相同特征的不同的对象:矩形.雇用记录.视频剪辑等.可以利用这些对象的相同特征为它们建立 ...
- 通信录列表+复杂Adapter分析
概述 最近写论文之余玩起了github,发现有个citypicker挺不错的,高仿了美团城市选择和定位的一些功能 地址链接 效果图如下: 自己手动写了一遍优化了一些内容,学到了一些姿势,下面对其中一些 ...
- Struct和Union在内存大小上的区别
名字起的不好,但是也不知道该叫什么好,题目如下: typedef union {];char c;} DATE; struct data { int i; DATE k; double j; }; i ...
- 管理xcode插件
1.打开终端 2.输入 open ~/Library/Application\ Support/Developer/Shared/Xcode/Plug-ins 3.出现 4.想删除那个就随意吧 ...
- VS2010断点调试技巧
设置断点:在如下图中的红色圆点处设置断点,红色圆点表示已经在这行设置断点.快捷键F9. 启动调试:按F5或者点击左边红框中的按钮.右边框是开始执行(不调试)Ctrl+F5. 调试工具栏:下面是工具 ...