ConcurrentHashMap实现原理总结

理论上,每个人知道hashmap不是线程安全的,并且它不应该被使用在多线程应用中。但是依然有人提出自己的能在上下文中使用hashmap的理论。一些人说他们仅仅是为了读数据并且map不会被写太多,不辛的是,当遇到一个并发问题时,并没有好的解释去支持。

通常,大多数人并没有懂得围绕在JMM和并发下的基本原理。一个人不能责备他们不知道他们的基本原理

public class MapTestTask implements Runnable {
	private Map hashMap;
	private Object value = new Object();
	public MapTestTask (Map map ){
		this.hashMap - map;
	}
	public void run (){
		hashMap.put(Thread.currentThread(),value);
		Ojbect retrieved = hashMap.get(Thread.currentThread());
		if(retrieved == null) {
			// Can it ever Happen
		}
	}
}

现在问题是当我们跑多线程时,是否能看到retrieved为空。

如果我们按顺序去看,它是不会发生的。但是当牵扯到并发时,这可能发生;我将给你一个复现这个场景的代码。

这是我的个人建议:不会当涉及到并发时,不要做太多设计。在并发环境中,没有一种理论能经历时间的考验。 粗略而简便的方法是,使用java自带的线程安全集合 在任何涉及到并发的地方。

最后我将给你

java JDK升级到1.8后有些集合类的实现有了变化,其中ConcurrentHashMap进行结构上的大调整。jdk1.6、1.7实现的共同点主要是通过采用分段锁Segment减少热点域来提高并发效率,

重要概念

在正式研究前,我们需要先知道几个重要参数,提前说明其值所代表的意义以便更好的讲解源码实现。

table所有数据都存在table中,table的容量会根据实际情况进行扩容,table[i]存放的数据类型有以下3种:
TreeBin 用于包装红黑树结构的结点类型

ForwardingNode 扩容时存放的结点类型,并发扩容的实现关键之一
Node 普通结点类型,表示链表头结点’

nextTable

扩容时用于存放数据的变量,扩容完成后会置为null。

sizeCtl

以volatile修饰的sizeCtl用于数组初始化与扩容控制,它有以下几个值:

当前未初始化:
	= 0  //未指定初始容量
	> 0  //由指定的初始容量计算而来,再找最近的2的幂次方。
		//比如传入6,计算公式为6+6/2+1=10,最近的2的幂次方为16,所以sizeCtl就为16。
初始化中:
	= -1 //table正在初始化
	= -N //N是int类型,分为两部分,高15位是指定容量标识,低16位表示
	     //并行扩容线程数+1,具体在resizeStamp函数介绍。
初始化完成:
	=table.length * 0.75  //扩容阈值调为table容量大小的0.75倍

其它的分析相应源码时再细说。

	static final int HASH_BITS = 0x7fffffff; // usable bits of normal node hash   //01111111_11111111_11111111_11111111
	
    static final int spread(int h) {
	    //无符号右移加入高位影响,与HASH_BITS做与操作保留对hash有用的比特位,有让hash>0的意思
        return (h ^ (h >>> 16)) & HASH_BITS;
    }

ConcurrentHashMap实现原理总结

1.7版本的ReentrantLock+Segment+HashEntry,

1.8版本中synchronized+CAS+HashEntry+红黑树。

1.数据结构:取消了Segment分段锁的数据结构,取而代之的是数组+链表+红黑树的结构。
2.保证线程安全机制:JDK1.7采用segment的分段锁机制实现线程安全,其中segment继承自ReentrantLock。JDK1.8采用CAS+Synchronized保证线程安全。
3.锁的粒度:原来是对需要进行数据操作的Segment加锁,现调整为对每个数组元素加锁(Node)。
4.链表转化为红黑树:定位结点的hash算法简化会带来弊端,Hash冲突加剧,因此在链表节点数量大于8时,会将链表转化为红黑树进行存储。
5.查询时间复杂度:从原来的遍历链表O(n),变成遍历红黑树O(logN)

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值