Concurrent 类型的容器

  • 内部很多操作使用 cas 优化,一般可以提供较高吞吐量
  • 弱一致性
    • 遍历时弱一致性,例如,当利用迭代器遍历时,如果容器发生修改,迭代器仍然可以继续进行遍历,但是旧数据
    • 求大小弱一致性,size 操作未必是 100% 准确

为什么会有ConcurrentHashMap

HashMap是线程不安全的,而使用 HashTable 虽然可以保证线程安全问题,但其是采用的是 synchronized 锁将整个 HashTable 中的数组锁住, 在多个线程中只允许一个线程访问 Put 或者 Get,效率低。
于是多线程的情况下 JDK 官方推荐使用 ConcurrentHashMap

ConcurrentHashMap底层如何实现

  1. ConcurrentHashMap 1.7 底层采用分段锁设计,即每个sagment对应一个锁,大致原理就是将一个大的 HashMap 分成 n 多个不同的小的 HashEntry。
  • 不同的 key 计算 index 如果没有发生冲突 则存放到不同的小的 HashEntry中 , 从而可以实现多线程,同时做 put 操作。
  • 但是如果多个线程同时 put 操作 key 发生了 index 冲突落到同一个小的 HashEntry中还是会发生竞争锁。
  • 缺点:sagment数值是懒惰初始化,不过其容量不支持扩充
  1. ConcurrentHashMap 1.8 版本 的put 操作取消 segment 分段设计,直接使用 Node 数组来保存数据
  • 当index 没有发生冲突使用 cas 锁
  • 当index 如果发生冲突时则 使用 synchronized

循环死链问题:
JDK1.7之前头插法导致的,后面1.8改为尾插法了。

值覆盖问题:
多线程计算索引是同一个位置,然后前一个的put操作被后一个put操作给覆盖了

所以在并发环境下还是建议使用concurrentHashMap