jdk8中ConcurrentHashMap的特点

  • get的时候如果发现桶的头节点hash值小于0,则代表是forwardingNode或者是TreeBIn,需要去新数组中查找或者走红黑树的逻辑(TreeBin里面有一个红黑色结构,包含一个TreeNode的root),这个treebin在树化的时候创造,赋值hash为-2;
  • put的时候如果发现痛的头节点hash值为-1,则表示正在扩容,则会去帮忙扩容。
  • 在remove和put的时候,如果是单线程,会对basecount进行操作,如果是多线程,则对cell[]数组中的累加单元进行操作(cas)。因此map统计的元素数量就是对这个数组进行累加,不一定是实时的。
  • Java 8 数组(Node) +( 链表 Node | 红黑树 TreeNode ) 以下数组简称(table),链表简称(bin)
  • 初始化,使用 cas 来保证并发安全,懒惰初始化 table 树化,当 table.length < 64 时,先尝试扩容,超过 64时,并且 bin.length > 8 时,会将链表树化,树化过程 会用 synchronized 锁住链表头
  • put,如果该 bin尚未创建,只需要使用 cas 创建 bin;如果已经有了,锁住链表头进行后续 put 操作,元素 添加至 bin 的尾部
  • get,无锁操作仅需要保证可见性,扩容过程中 get 操作拿到的是 ForwardingNode 它会让 get 操作在新 table进行搜索 扩容,扩容时以 bin 为单位进行,需要对 bin 进行 synchronized,但这时妙的是其它竞争线程也不是无事可做,它们会帮助把其它 bin 进行扩容,扩容时平均只有 1/6 的节点会把复制到新 table 中
  • size,元素个数保存在 baseCount 中,并发时的个数变动保存在 CounterCell[] 当中。最后统计数量时累加 即可
  • JDK 7 ConcurrentHashMap 它维护了一个 segment 数组,每个 segment 对应一把锁 优点:如果多个线程访问不同的segment,实际是没有冲突的,这与 jdk8 中是类似的 缺点:Segments数组默认大小为16,这个容量初始化指定后就不能改变了,并且不是懒惰初始化 。segment 继承了可重入(ReentrantLock)发生在 put 中,因为此时已经获得了锁,因此 rehash 时不需要考虑线程安全
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值