【JUC源码】并发容器:关于 ConcurrentHashMap 的几个问题

ConcurrentHashMap 系列:

在下面有什么不理解的地方,可以参考源码进行理解。

1.ConcurrentHashMap 和 HashMap 的相同点和不同点?

  • 相同点:

    • 都是数组 + 链表 +红黑树的数据结构,所以基本操作的思想相同;
    • 都实现了 Map 接口,继承了 AbstractMap 抽象类,所以两者的方法大多都是相似的,可以互相切换。
  • 不同点:

    • ConcurrentHashMap 是线程安全的,在多线程环境下,无需加锁,可直接使用;
    • 数据结构上,ConcurrentHashMap 多了转移节点,主要用于保证扩容时的线程安全。

2.ConcurrentHashMap 通过哪些手段保证了线程安全?

答:主要有以下几点:

  1. volatile:储存 Map 数据的数组被 volatile 关键字修饰,一旦被修改(扩容后),立马就能通知其他线程,因为是数组,所以需要改变其内存值,才能真正的发挥出 volatile 的可见特性;
  2. 自旋:自旋保证了操作一定会成功(for),如 putVal(),transfer()
  3. CAS:CAS相当于乐观锁,保证了只有单线程对数据操作,如 put() 时,如果计算出来的数组下标索引没有值的话,采用无限 for 循环 + CAS 算法,来保证一定可以新增成功,又不会覆盖其他线程 put 进去的值;
  4. 分段锁:在进行新增与扩容时,对当前槽点上锁,保证只有当前线程才能对槽点上的链表或红黑树进行操作
  5. 如果 put 的节点正好在扩容,会等待扩容完成之后,再进行 put ,保证了在扩容时,老数组的值不会发生变化;
  6. 红黑树旋转时,会锁住根节点,保证旋转时的线程安全。

3.描述一下 CAS 算法在 ConcurrentHashMap 中的应用?

答:CAS 其实是一种乐观锁,一般有三个值,分别为:赋值对象,原值,新值,在执行的时候,会先判断内存中的值是否和原值相等,相等的话把新值赋值给对象,否则赋值失败,整个过程都是原子性操作,没有线程安全问题。

ConcurrentHashMap 的 putVal() 方法中,有使用到 CAS ,是结合无限 for 循环一起使用的,步骤如下:

  1. 计算出数组索引下标,拿出下标对应的原值;
  2. CAS 覆盖当前下标的值,赋值时,如果发现内存值和 1 拿出来的原值相等,执行赋值,退出循环,否则不赋值,转到 3;
  3. 进行下一次 for 循环,重复执行 1,2,直到成功为止。

可以看到这样做的好处,第一是不会盲目的覆盖原值,第二是一定可以赋值成功。

4.ConcurrentHashMap 是如何发现当前槽点正在扩容的?

答:ConcurrentHashMap 新增了一个节点类型,叫做转移节点,当我们发现当前槽点是转移节点时(转移节点的 hash 值是 -1),即表示 Map 正在进行扩容。

5.发现槽点正在扩容时,put 操作会怎么办?

答:无限 for 循环,或者走到扩容方法中去,帮助扩容,一直等待扩容完成之后,再执行 put 操作。

6.两种 Map 扩容时,有何区别?

答:区别很大,HashMap 是直接在老数据上面进行扩容,多线程环境下,会有线程安全的问题,而 ConcurrentHashMap 就不太一样,扩容过程是这样的:

  1. 从数组的队尾开始拷贝
  2. 拷贝数组的槽点时,先把原数组槽点锁住
  3. 拷贝成功到新数组时,把原数组槽点赋值为转移节点
  4. 直到所有数组数据都拷贝到新数组时,直接把新数组整个赋值给数组容器,拷贝完成

简单来说,通过扩容时给槽点加锁,和发现槽点正在扩容就等待的策略,保证了 ConcurrentHashMap 可以慢慢一个一个槽点的转移,保证了扩容时的线程安全。

7.ConcurrentHashMap 在 Java 7 和 8 中关于线程安全的做法有什么不同?

答:非常不一样,拿 put 方法为例,Java 7 的做法是:

  1. 把数组进行分段,找到当前 key 对应的是那一段;
  2. 将当前段锁住,然后再根据 hash 寻找对应的值,进行赋值操作。

Java 7 的做法比较简单,缺点也很明显,就是当我们需要 put 数据时,我们会锁住改该数据对应的某一段,这一段数据可能会有很多,比如我只想 put 一个值,锁住的却是一段数据,导致这一段的其他数据都不能进行写入操作,大大的降低了并发性的效率。

Java 8 解决了这个问题,从锁住某一段,修改成锁住某一个槽点,提高了并发效率。不仅仅是 put,删除也是,仅仅是锁住当前槽点,缩小了锁的范围,增大了效率。

猜你喜欢

转载自blog.csdn.net/qq_33762302/article/details/114421393