Java 非线程安全的HashMap如何在多线程中使用
Java 非线程安全的HashMap如何在多线程中使用
HashMap 是非线程安全的。在多线程条件下,容易导致死循环,具体表现为CPU使用率100%。因此多线程环境下保证 HashMap 的线程安全性,主要有如下几种方法:
- 使用 java.util.Hashtable 类,此类是线程安全的。
- 使用 java.util.concurrent.ConcurrentHashMap,此类是线程安全的。
- 使用 java.util.Collections.synchronizedMap() 方法包装 HashMap object,得到线程安全的Map,并在此Map上进行操作。
- 自己在程序的关键代码段加锁,保证多线程安全(不推荐)
接下来分析上面列举的几种方法实现并发安全的 HashMap 的原理:
(一)java.util.Hashtable类:
查看该类的源码
public synchronized V get(Object key) {
…… //具体的实现省略,请参考 jdk实现
}
public synchronized V put(K key, V value) {
…… //具体的实现省略,请参考 jdk实现
}
public synchronized V remove(Object key) {
…… //具体的实现省略,请参考 jdk实现
}
上面是 Hashtable 类提供的几个主要方法,包括 get(),put(),remove() 等。注意到每个方法本身都是 synchronized 的,不会出现两个线程同时对数据进行操作的情况,因此保证了线程安全性,但是也大大的降低了执行效率。因此是不推荐的。
(二)使用 java.util.concurrent.ConcurrentHashMap 类:
该类是 HashMap 的线程安全版,与 Hashtable 相比, ConcurrentHashMap 不仅保证了访问的线程安全性,而且在效率上有较大的提高。
ConcurrentHashMap的数据结构如下:

可以看出,相对 HashMap 和 Hashtable, ConcurrentHashMap 增加了Segment 层,每个Segment 原理上等同于一个 Hashtable, ConcurrentHashMap 等同于一个 Segment 的数组。下面是 ConcurrentHashMap 的 put 和 get 方法:
final Segment<K,V> segmentFor(int hash) {
return segments[(hash >>> segmentShift) & segmentMask];
}
public V put(K key, V value) {
if (value == null)
throw new NullPointerException();
int hash = hash(key.hashCode());
return segmentFor(hash).put(key, hash, value, false);
}
public V get(Object key) {
int hash = hash(key.hashCode());
return segmentFor(hash).get(key, hash);
}
向 ConcurrentHashMap 中插入数据(put) 或者 读取数据(get),首先都要将相应的 Key 映射到对应的 Segment,因此不用锁定整个类, 只要对单个的 Segment 操作进行上锁操作就可以了。理论上如果有 n 个 Segment,那么最多可以同时支持 n 个线程的并发访问,从而大大提高了并发访问的效率。
Java 非线程安全的HashMap如何在多线程中使用的更多相关文章
- 非线程安全的HashMap 和 线程安全的ConcurrentHashMap
在平时开发中,我们经常采用HashMap来作为本地缓存的一种实现方式,将一些如系统变量等数据量比较少的参数保存在HashMap中,并将其作为单例类的一个属性.在系统运行中,使用到这些缓存数据,都可以直 ...
- [Java集合] 彻底搞懂HashMap,HashTable,ConcurrentHashMap之关联.
注: 今天看到的一篇讲hashMap,hashTable,concurrentHashMap很透彻的一篇文章, 感谢原作者的分享. 原文地址: http://blog.csdn.net/zhanger ...
- Java并发基础08. 造成HashMap非线程安全的原因
在前面我的一篇总结(6. 线程范围内共享数据)文章中提到,为了数据能在线程范围内使用,我用了 HashMap 来存储不同线程中的数据,key 为当前线程,value 为当前线程中的数据.我取的时候根据 ...
- JAVA中的线程安全与非线程安全
原文:http://blog.csdn.net/xiao__gui/article/details/8934832 ArrayList和Vector有什么区别?HashMap和HashTable有什么 ...
- java 多线程 线程安全及非线程安全的集合对象
一.概念: 线程安全:就是当多线程访问时,采用了加锁的机制:即当一个线程访问该类的某个数据时,会对这个数据进行保护,其他线程不能对其访问,直到该线程读取完之后,其他线程才可以使用.防止出现数据不一致或 ...
- Java多线程之非线程安全
在Java多线程中我会重点总结五个如下的技术点: 1.非线程安全是如何出现的 2.synchronized对象监视器为Objec时的使用 3.synchronized对象监视器为Class时的使用 4 ...
- java中线程安全和非线程安全的集合
线程安全 非线程安全 Collection Vector ArrayList.LinkedList HashSet.TreeSet Map HashTable HashMap.TreeMap 字符串 ...
- Java线程安全和非线程安全
ArrayList是非线程安全的,Vector是线程安全的:HashMap是非线程安全的,HashTable是线程安全的:StringBuilder是非线程安全的,StringBuffer是线程安全的 ...
- 为什么JAVA虚拟机分为线程共享和非线程共享?
大多数 JVM 将内存区域划分为 Method Area(Non-Heap)(方法区) ,Heap(堆) , Program Counter Register(程序计数器) , VM Stack(虚拟 ...
随机推荐
- Uva 12436 Rip Van Winkle's Code
Rip Van Winkle was fed up with everything except programming. One day he found a problem whichrequir ...
- javaWeb中URLEncoder.encode空格问题
近期开发一个在线坐席的功能.发现推送的消息中空格变成了+ .查询发现URLEncoder.encode的问题.曾经用的时候也没注意过,解决的方法网上是对URLEncoder.encode的之后的字符串 ...
- Sqoop2安装记录
我是採用的源代码编译的包安装的, 主要是考虑到会对部分功能做裁剪或增强, 详细源代码编译方式能够參考另外一篇博文<编译Sqoop2错误解决>.然后从dist/target文件夹下拷贝sqo ...
- springmvc中@PathVariable传Double精度丢失
页面请求 http://localhost:8080/test/3.201 后端接受数据 /** * 测试 * * @param number */ @RequestMapping(value = & ...
- intellij安装lombok插件,解决注解@Slf4j注入后找不到变量log
1.进入设置 2.搜索插件 3.安装
- seleniumPO模式
一.框架目录结构 二.代码 2.1page层代码 package com.mianshui.page; import org.openqa.selenium.WebElement; import or ...
- mysql创建新用户及新用户不能本地登陆的问题
最近在搭建hadoop集群,主节点上面安装的MySQL数据库,对着方面不熟悉,为hive.Ooize等服务统一使用的root账号和密码,为了安全一些库对于某些用户是不可见的,所以需要针对不同的服务设置 ...
- 如何检测mvc性能和sql语句
mvc中使用linq如何检测sql语句 .net中使用mvc开发已经是一种趋势,不仅仅是.net ,java 等越来越多的开发者更倾向于mvc这种开发模式,在.net mvc 使用linq非常方便,各 ...
- 程序员的自我救赎---11.1:RPC接口使用规范
<前言> (一) Winner2.0 框架基础分析 (二)PLSQL报表系统 (三)SSO单点登录 (四) 短信中心与消息中心 (五)钱包系统 (六)GPU支付中心 (七)权限系统 (八) ...
- & 与 kill -3
mysqld_safe --defaults-file=/app/3307/my.cnf 2>&1 1>/dev/null & 将mysqld服务进程放入后台后, 因为忘记 ...