JDK1.0引入了第一个关联的集合类HashTable,它是线程安全的。HashTable的所有方法都是同步的。
JDK2.0引入了HashMap,它提供了一个不同步的基类和一个同步的包装器synchronizedMap。synchronizedMap被称为有条件的线程安全类。
JDK5.0util.concurrent包中引入对Map线程安全的实现ConcurrentHashMap,比起synchronizedMap,它提供了更高的灵活性。同时进行的读和写操作都可以并发地执行。

在平时开发中,我们经常采用HashMap来作为本地缓存的一种实现方式,将一些如系统变量等数据量比较少的参数保存在HashMap中,并将其作为单例类的一个属性。在系统运行中,使用到这些缓存数据,都可以直接从该单例中获取该属性集合。但是,最近发现,HashMap并不是线程安全的,如果你的单例类没有做代码同步或对象锁的控制,就可能出现异常。

首先看下在多线程的访问下,非现场安全的HashMap的表现如何,在网上看了一些资料,自己也做了一下测试:

public class MainClass {
public static final HashMap<String, String> firstHashMap = new HashMap<String, String>(); public static void main(String[] args) throws InterruptedException {
Thread t1 = new Thread() {
public void run() {
for (int i = 0; i < 250; i++) {
firstHashMap.put(String.valueOf(i), String.valueOf(i));
}
}
};
Thread t2 = new Thread() {
public void run() {
for (int j = 250; j < 500; j++) {
firstHashMap.put(String.valueOf(j), String.valueOf(j));
}
}
};
t1.start();
t2.start();
Thread.currentThread().sleep(1000);
for (int l = 0; l < 500; l++) {
if (!String.valueOf(l).equals(firstHashMap.get(String.valueOf(l)))) {
System.out.println(String.valueOf(l) + ":" + firstHashMap.get(String.valueOf(l)));
}
}
}
}

  上面的代码在多次执行后,发现表现很不稳定,有时没有异常文案打出,有时则有个异常出现:

为什么会出现这种情况,主要看下HashMap的实现:

从代码中,可以看到,如果发现哈希表的大小超过阀值threshold,就会调用resize方法,扩大容量为原来的两倍,而扩大容量的做法是新建一个Entry[]:

一般我们声明HashMap时,使用的都是默认的构造方法:HashMap<K,V>,看了代码你会发现,它还有其它的构造方法:HashMap(int initialCapacity, float loadFactor),其中参数initialCapacity为初始容量,loadFactor为加载因子,而之前我们看到的threshold = (int)(capacity * loadFactor); 如果在默认情况下,一个HashMap的容量为16,加载因子为0.75,那么阀值就是12,所以在往HashMap中put的值到达12时,它将自动扩容两倍,如果两个线程同时遇到HashMap的大小达到12的倍数时,就很有可能会出现在将oldTable转移到newTable的过程中遇到问题,从而导致最终的HashMap的值存储异常。

JDK1.0引入了第一个关联的集合类HashTable,它是线程安全的。HashTable的所有方法都是同步的。
JDK2.0引入了HashMap,它提供了一个不同步的基类和一个同步的包装器synchronizedMap。synchronizedMap被称为有条件的线程安全类。
JDK5.0util.concurrent包中引入对Map线程安全的实现ConcurrentHashMap,比起synchronizedMap,它提供了更高的灵活性。同时进行的读和写操作都可以并发地执行。

所以在开始的测试中,如果我们采用ConcurrentHashMap,它的表现就很稳定,所以以后如果使用Map实现本地缓存,为了提高并发时的稳定性,还是建议使用ConcurrentHashMap。
====================================================================

参考:http://www.blogjava.net/lukangping/articles/331089.html

http://www.cnblogs.com/ITtangtang/p/3948786.html

最新文章

  1. Autofac - 组件
  2. 有关WAMPSERVER 环境搭建 如何修改端口,MySQL数据库的修改
  3. 《OD学hadoop》第四周0716
  4. Parallel并行运算实例
  5. 前端开发构建工具gulp的安装使用
  6. ASP.Net开发WebAPI跨域访问(CORS)的精简流程
  7. SAP smartform 实现打印条形码
  8. .Net高级进阶,在复杂的业务逻辑下,如何以最简练的代码,最直观的编写事务代码?
  9. 关于userInteractionEnabled的属性的理解
  10. Django部署方法
  11. AES
  12. SQL Server 中的6种事务隔离级别简单总结
  13. Linux下rsync daemon模式下的错误汇总
  14. Properties集合_修改配置信息
  15. 2018 ACM 网络选拔赛 南京赛区
  16. poj 3233 S = A + A^2 + A^3 + … + A^k A是一个n X n矩阵 (矩阵快速幂)
  17. java并发基础(三)--- 任务执行
  18. spacemacs怎样配置编辑器显示行号?
  19. 关于在ubuntu下配置AMD显卡驱动的总结
  20. Kafka设计解析(十七)Kafka 0.11客户端集群管理工具AdminClient

热门文章

  1. 【BZOJ-2095】Bridge 最大流 + 混合图欧拉回路 + 二分
  2. Jenkins项目构建结果通知Email的替代方案Wall Display插件
  3. C++实现类似飞鸽的内网聊天工具,采用多播的协议实现
  4. jboss wildfly 外网访问
  5. 第1个linux驱动___打印&quot;hello world&quot;
  6. javascript应用之如何判断一个数为素数
  7. 符号(void *)何解?符号(void **)又何解??
  8. BZOJ3082: Graph2
  9. js002-在HTML中使用JavaScript
  10. setInterval js