JAVA之ConcurrentHashMap和HashMap关于线程安全问题分析

说起HashMap和ConcurrentHashMap,我们很多人都会知道HashMap是线程不安全的,ConcurrentHashMap是线程安全的;

看下面的代码示例:

    public static void main(String[] args) {
//		Map<String,String> map = new ConcurrentHashMap<>();
		Map<String,String> map = new HashMap<>();
		int n=100;
		CountDownLatch cdl = new CountDownLatch(n);
		for(int i=0; i<n; i++) {
			new Thread(()->{
				for(int j=0;j<100;j++) {
					String key = UUID.randomUUID().toString();
					map.put(key, key);
				}
				cdl.countDown();
			}).start();
		}
		try {
			cdl.await();
		} catch (InterruptedException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		System.out.println(map.size());
	}

代码中用了100个线程,每个线程put100次,结果会发现,使用ConcurrentHashMap时,结果就是预期的10000,但是使用HashMap时,会发现结果总是小于10000,说明它丢失了部分数据;

HashMap线程不安全具体是哪里的不安全呢?而ConcurrentHashMap又是怎么保证线程安全的?

看过源码的人应该都知道,HashMap内部数据结构就是一个数组+链表(jdk1.8后链表长度超过阈值后会转为红黑树)的结构;

HashMap的put全过程如下图所示(为了画图方便,不完全等同于源码逻辑):

整个put过程中,有很多都是线程不安全的行为,简单列举两点如下:

1、初始化数组不安全,多线程环境中B线程可能覆盖掉A线程

2、添加元素时不安全

同理,在链表上添加节点或者树上添加节点时以及数组扩容等,都会存在线程不安全问题。

ConcurrentHashMap的put过程类似于HashMap,那它又是如何确保上诉这些环节的线程安全呢?

如下面简略图,关键节点处都使用到了锁,有的是CAS乐观锁,有的是synchronized锁,使用synchronized锁时,锁对象就是当前数组下标位置的第一个元素,所以数组length有多大,就可以支持多大的并发写。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 4
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值