Java并发容器ConcurrentMap

ConcurrentMap

ConcurrentMap接口是线程安全的Map接口,ConcurrentHashMap是HashMap的线程安全版本。

ConcurrentHashMap

在JDK7的时候是将ConcurrentHashMap采用分段锁,将一个整体分为16段HashTable,每个段是一个Segment,提高了并发度;JDK8取消了Segment分段结构,改成了与HashMap一样的数组+链表+红黑树,实现对每一段数据进行加锁,也减少了并发冲突的概率。

JDK7
Segment

在jdk8之前concurrentHashMap使用该对象进行分段加锁,降低了锁的粒度,使得并发效率提高,Segment本身也相当于一个HashMap,Segment包含一个HashEntry数组,数组中每个HashEntry既是一个键值对,又是一个链表的头结点。

get方法
  • 根据key做hash运算,得到hash值

  • 通过hash值,定位到对应的segment对象

  • 再次通过hash值,定位到segment当中数组的具体位置

put方法
  • 根据key做hash运算,得到hash值

  • 通过hash值,定位到对应的segment对象

  • 获取可重入锁

  • 再次通过hash值,定位到segment当中数组的具体位置

  • 插入或覆盖hashEntry对象

  • 释放锁

但是使用这种方式实现需要进行两次hash操作,第一次hash操作找到对应的segment,第二次hash操作定位到元素所在链表的头部。

JDK8

在jdk8的时候参考了HashMap的设计,采用了数组+链表+红黑树的方式,内部大量采用CAS操作,舍弃了分段锁的思想。

CAS

CAS是compare and swap的缩写,也就是我们所说的比较交换,CAS属于乐观锁。

CAS包含三个操作数,---内存中的值(V),预期原值(A),新值(B)  如果内存中的值和A的值一样,就可以将内存中的值更新为B。CAS通过无限循环来获取数据,一直到V和A一致为止。

乐观锁

乐观锁会很乐观的认为不会出现并发问题,所以采用无锁的机制来进行处理,比如通过给记录加version来获取数据,性能比悲观锁要高。

悲观锁

悲观锁会很悲观的认为肯定会出现并发问题,所以会将资源锁住,该资源只能有一个线程进行操作,只有前一个获得锁的线程释放锁之后,下一个线程才可以访问。

源码分析 

// 表示整个hash表,初始化阶段是在第一次插入的时候,容量总是2的次幂
transient volatile Node<K,V>[] table;

// 下一个使用的表 只有在扩容的时候非空,其他情况都是null
private transient volatile Node<K,V>[] nextTable;

/**
 * Base counter value, used mainly when there is no contention,
 * but also as a fallback during table initialization
 * races. Updated via CAS.
 */
private transient volatile long baseCount;


// 用于初始化和扩容控制
// 0:默认值
// -1:正在初始化
// 大于0:为hash表的阈值
// 小于-1:有多个线程在进行扩容 该值为 -(1+正在扩容的线程数)
private transient volatile int sizeCtl;

/**
 * The next table index (plus one) to split while resizing.
 */
private transient volatile i
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值