深入理解ConcurrentHashMap

本文深入探讨了ConcurrentHashMap的工作原理,对比了HashMap和HashTable,详细解释了ConcurrentHashMap如何通过锁分段技术实现高并发访问,以及在JDK1.8中采用的数组、链表、红黑树和CAS操作等优化手段。
摘要由CSDN通过智能技术生成

ConcurrentHashMap是线程安全并且高效的一种容器,下面就来研究一下ConcurrentHashMap为什么既能够保证线程安全,又可以保证高效的操作。

1、ConcurrentHashMap使用原因

为什么要使用ConcurrentHashMap,首先需要和HashMap以及HashTable进行比较。

HashMap线程不安全的原因

在多线程的情况下,HashMap的操作会引起死循环,导致CPU的占有量达到100%,所以在并发的情况下,一般不使用HashMap。

至于为什么引起死循环,是因为HashMap的Entry链表会形成链式的结构,一旦形成了Entry的链式结构,链表中的next指针就会一直不为空,这样就会导致死循环。

不使用HashTable的原因

HashTable中使用synchronize来保证线程安全,即当有一个线程拥有锁的时候,其它的线程都会进入阻塞或者轮询状态,这样会使得效率越来越低。

使用ConcurrentHashMap的锁分段技术可以有效地提高并发访问率

HashTable访问效率低下的原因,就是因为所有的线程在竞争同一把锁。如果容器中有多把锁,不同的乐山乐山定不同的位置,这样线程间就不会存在锁的竞争,这样就可以有效地提高并发访问效率,这就是ConcurrentHashMap所使用的锁分段技术。

将数据一段一段地存储,然后为每一段都配一把锁,当一个线程只是占用其中的一个数据段时,其它段的数据也能被其它线程访问。

2、ConcurrentHashMap的结构

ConcurrentHashMap是由Segment和HashEntry组成的。Segment是一种可重入的锁(Reentranlock),Segment在其中扮演锁的角色;HashEntry用于存储数据。一个ConcurrentHashMap包括一个Segment数组,一个Segment元素包括一个HashEntry数组,HashEntry是一种链表型的结构,每一个Segment维护着HashEntry数组中的元素,当要对HashEntry中的数据进行修改的时候,必须先要获得与它对应的Segment

ConcurrentHashMap的体系结构

在这样的机制下,当修改该容器的不同的段时,就不会存在并发的问题。如图可知,得到一个元素需要进行两次hash操作,第一次得到Segment,第二次得到HashEntry中的链表头部,这样会使得Hash的过程比普通的HashMap要长。

写操作的时候可以只能元素所在的Segment进行加锁即可,不会影响到其它的Segment;这样,在最理想的情况下,ConcurrentHashMap可以最高同时支持Segment数量大小的写操作(刚好这些写操作都非常平均地分布在所有的Segment上)。

3、JDK1.8的ConcurrentHashMap的原理

JDK1.8的ConcurrentHashMap参考了1.8HashMap的实现方式,采用了数组、链表、红黑树的实现方式,其中大量地使用CAS操作。CAS(compare and swap),也就是比较交换。CAS是一种基于锁的操作,而且是乐观锁。Java的锁中分为乐观锁和悲观锁。(悲观锁是指将资源锁住,等待当前占用锁的线程释放掉锁,另一个线程才能够获取线程;乐观锁是通过某种方式不加锁,比如说添加version字段来获取数据)

CAS操作包含了三个操作数——内存位置、预期的原值、新值。如果内存的值和预期的原值是一致的,那么就转化为新值。CAS是通过不断地循环来获取新值,如果A线程中的值被另一个线程修改了,那么A线程就需要自旋,到下次循环才有可能执行。

static class Node<K, V> implements Map.Entry<K, V> {
    final int hash;
    final K key;
    volatile V val;
    volatile Node<K, V> next;
    Node(int hash, K key, V val, Node<K, V> next) {
        this.hash = hash;
        this.key = key;
        this.val = val;
        this.next = next;
    }
}

这是JDK1.8中的Node节点,其中的val和next都通过可见性修饰。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值