ConcurrentHashMap底层原理

ConcurrentHashMap

一、简介

出自JDK5新引进的Concurrent包,ConcurrentHashMap主要解决了两个问题:

  1. 相较于只使用synchronized的HashTable提高了性能,根据具体场景进行不同的设计,尽量避免了重量级锁。
  2. 不同于HashMap,采用了 fail-safe 弱一致性迭代器,再迭代器使用过程中,可以对元素进行更新操作。

简单说就是可以一个可以并发操作保证安全性并且性能不差的HashMap。

二、HashMap,HashTable,ConcurrentHashMap对比

在这里插入图片描述

可以看到HashTable基本上被淘汰,因为synchronized效率很低。ConcurrentHashMap可以做到读取数据不加锁,并且在写操作的时候能将锁粒度尽可能的小,关键在于使用了锁分离技术,对不同部分进行加锁操作。

三、实现原理

jdk1.8版本下实现原理:

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

读操作基于volatile保证了线程安全。volatile保证可见性,使得每次读取都是直接从内存读取。

再看put操作。这里只截取到他正常put元素时的部分,不关注其他操作。

else if ((f = tabAt(tab, i = (n - 1) & hash)) == null) {
                if (casTabAt(tab, i, null,
                             new Node<K,V>(hash, key, value, null)))
                    break;                   // no lock when adding to empty bin
            }

这是当hash函数计算出来的存放下标为null(没有元素时),会调用casTabAt,继续跟踪。

    static final <K,V> boolean casTabAt(Node<K,V>[] tab, int i,
                                        Node<K,V> c, Node<K,V> v) {
        return U.compareAndSwapObject(tab, ((long)i << ASHIFT) + ABASE, c, v);
    }

//U是Unsafe对象
private static final sun.misc.Unsafe U;

发现最终是调用Unsafe类下的compareAndSwapObject。

            else {
                V oldVal = null;
                synchronized (f) {
                    if (tabAt(tab, i) == f) {
                        if (fh >= 0) {
                            binCount = 1;
                            for (Node<K,V> e = f;; ++binCount) {

else逻辑就是当计算出来的存放下标不为null的情况下,当前很多细节暂时不关注。f是这里下标位置的链表头元素,对该对象上锁,保证了线程安全。

通过阅读源码,jdk1.8的ConcurrentHashMap总结如下:

  • 底层数据结构和HashMap一样。
  • 支持并发的实现原理是:CAS+synchronized
  • put操作时,通过key对象的hashcode计算出存放数组的下标,如果没有Node,则使用CAS操作尝试插入元素,失败则自旋到插入成功为止;如果存在Node,则使用synchronized锁住该Node对象,再进行插入操作。
  • value使用volatile保证可见性,保证了读操作的线程安全。

jdk1.7版本下实现原理:

在这里插入图片描述

与1.8大有不同,采用了segment分段锁技术,在多线程并发操作时,对同一个segment进行同步加锁,保证数据的安全。可以看到Segment继承自ReentrantLock,其加锁的方式也是基于ReentrantLock锁机制

以上都是不考虑扩容情况,如果发生了扩容,则情况就非常复杂了;简单说,就是它在扩容的时候,会保留两个 table,一个用于扩容,一个还在提供服 务,做到真正的不停机。

这里放一些面试题供大家参考

  1. ConcurrentHashMap的读是否要加锁,为什么?

  2. ConcurrentHashMap的锁分段技术?

  3. ConcurrentHashMap的迭代器是强一致性的迭代器还是弱一致性的迭代器?

  4. Mashmap和ConcurrentHashMap怎么确定key的唯一性?

  5. HashTable和HashMap、ConcurrentHashMap?

  6. ConcurrentHashMap的原理使用?

  7. ConcurrentHashMap在jdk1.8做了哪些优化?

、ConcurrentHashMap?
6. ConcurrentHashMap的原理使用?

  1. ConcurrentHashMap在jdk1.8做了哪些优化?

  2. ConcurrentHashMap如何实现线程安全?

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值