【集合学习ConcurrentHashMap】ConcurrentHashMap集合学习

ConcurrentHashMap集合学习

一、JDK1.7 和 1.8 版本ConcurrenHashMap对比分析

JDK 1.7版本

在JDK 1.7版本ConcurrentHashMap使用了分段锁的方式(对Segment进行加锁),其实际结构为:Segment数组 + HashEntry数组 + 链表。由很多个 Segment 组合,而每一个 Segment 是一个类似于 HashMap 的结构,其可以进行扩容。但是 Segment 的个数一旦初始化就不能改变,默认 Segment 的个数是 16 个,你也可以认为 ConcurrentHashMap 默认支持最多 16 个并发线程。
(Segment 继承了 ReentrantLock,所以 Segment 内部可以很方便的获取锁)
在这里插入图片描述

JDK 1.8版本

JDK1.8版本 中的 ConcurrentHashMap 使用的 Synchronized 锁 + CAS 的机制。结构也由 Java7 中的 Segment 数组 + HashEntry 数组 + 链表 进化成了 Node 数组 + 链表 / 红黑树,Node 是类似于一个 HashMap 的结构。它的冲突再达到一定大小时会转化成红黑树,在冲突小于一定数量时又退回链表。

Java 1.8 在链表长度超过一定阈值 8 时将链表(寻址时间复杂度为 O(N))转换为红黑树(寻址时间复杂度为 O(log(N)))。Java 8 中,锁粒度更细,synchronized 只锁定当前链表或红黑二叉树的首节点,这样只要 hash 不冲突,就不会产生并发,就不会影响其他 Node 的读写,效率大幅提升。

在这里插入图片描述

二、JDK 1.8版本源码分析

(一)put 方法

  • 根据 key 计算出 hashcode 。便于之后进一步确定Node的位置。
  • 判断是否需要进行初始化。 ConcurrentHashMap 的初始化是通过自旋和 CAS 操作完成的。
  • 即为当前 key 定位出的Node,如果为空表示当前位置可以写入数据,利用 CAS 尝试写入失败则自旋保证成功
  • 如果当前位置的 hashcode ==MOVED == -1,则需要进行扩容。
  • 如果都不满足,则利synchronized 锁写入数据。(synchronized锁当前Node节点,相比与JDK1.7版本的segment分段锁,锁粒度小)
  • 如果数量大于一定长度TREEIFY_THRESHOLD 则要执行树化方法,在 treeifyBin 中会首先判断当前数组长度 ≥64时才会将链表转换为红黑树。
public V put(K key, V value) {return putVal(key, value, false);
}/** Implementation for put and putIfAbsent */
final V putVal(K key, V value, boolean onlyIfAbsent) {// key 和 value 不能为空if (key == null || value == null) throw new NullPointerException();int hash = spread(key.hashCode());int binCount = 0;for (Node<K,V>[] tab = table;;) {// f = 目标位置元素Node<K,V> f; int n, i, fh;// fh 后面存放目标位置的元素 hash 值if (tab == null || (n = tab.length) == 0)// 数组桶为空,初始化数组桶(自旋+CAS)tab = initTable();else if ((f = tabAt(tab, i = (n - 1) & hash)) == null) {// 桶内为空,CAS 放入,不加锁,成功了就直接 break 跳出if (casTabAt(tab, i, null,new Node<K,V>(hash, key, value, null)))break;  // no lock when adding to empty bin}else if ((fh = f.hash) == MOVED)tab = helpTransfer(tab, f);else {V oldVal = null;// 使用 synchronized 加锁加入节点synchronized (f) {if (tabAt(tab, i) == f) {// 说明是链表if (fh >= 0) {binCount = 1;// 循环加入新的或者覆盖节点for (Node<K,V> e = f;; ++binCount) {K ek;if (e.hash == hash &&((ek = e.key) == key ||(ek != null && key.equals(ek)))) {oldVal = e.val;if (!onlyIfAbsent)e.val = value;break;}Node<K,V> pred = e;if ((e = e.next) == null) {pred.next = new Node<K,V>(hash, key,value, null);break;}}}else if (f instanceof TreeBin) {// 红黑树Node<K,V> p;binCount = 2;if ((p = ((TreeBin<K,V>)f).putTreeVal(hash, key,value)) != null) {oldVal = p.val;if (!onlyIfAbsent)p.val = value;}}}}if (binCount != 0) {if (binCount >= TREEIFY_THRESHOLD)treeifyBin(tab, i);if (oldVal != null)return oldVal;break;}}}addCount(1L, binCount);return null;
}

(二)get方法

总结一下 get 过程:

  • 根据 hash 值计算位置。
  • 查找到指定位置,如果头节点就是要找的,直接返回它的 value。
  • 如果头节点 hash 值小于 0,说明正在扩容或者是红黑树,查找之。
  • 如果是链表,遍历查找之。
public V get(Object key) {Node<K,V>[] tab; Node<K,V> e, p; int n, eh; K ek;// key 所在的 hash 位置int h = spread(key.hashCode());if ((tab = table) != null && (n = tab.length) > 0 &&(e = tabAt(tab, (n - 1) & h)) != null) {// 如果指定位置元素存在,头结点hash值相同if ((eh = e.hash) == h) {if ((ek = e.key) == key || (ek != null && key.equals(ek)))// key hash 值相等,key值相同,直接返回元素 valuereturn e.val;}else if (eh < 0)// 头结点hash值小于0,说明正在扩容或者是红黑树,find查找return (p = e.find(h, key)) != null ? p.val : null;while ((e = e.next) != null) {// 是链表,遍历查找if (e.hash == h &&((ek = e.key) == key || (ek != null && key.equals(ek))))return e.val;}}return null;
}

三、JDK 1.7 和 JDK 1.8 的 ConcurrentHashMap 实现有什么不同?

  • 线程安全实现方式:JDK 1.7 采用 Segment 分段锁来保证安全, Segment 是继承自 ReentrantLock。JDK1.8 放弃了 Segment 分段锁的设计,采用 Node + CAS + synchronized 保证线程安全,锁粒度更细,synchronized 只锁定当前链表或红黑二叉树的首节点。
  • Hash 碰撞解决方法 : JDK 1.7 采用拉链法,JDK1.8 采用拉链法结合红黑树(链表长度超过一定阈值时,将链表转换为红黑树)。
  • 并发度:JDK 1.7 最大并发度是 Segment 的个数,默认是 16。JDK 1.8 最大并发度是 Node 数组的大小,并发度更大。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://xiahunao.cn/news/1621865.html

如若内容造成侵权/违法违规/事实不符,请联系瞎胡闹网进行投诉反馈,一经查实,立即删除!

相关文章

I^2C总线简介

总共有五种工作状态&#xff1a; A&#xff1a;总线非忙状态 该状态时数据线&#xff08;SDA&#xff09;和时钟线&#xff08;SCL&#xff09;都保持高电平。 B&#xff1a;启动状态 当时钟线&#xff08;SCL&#xff09;为高电平状态时&#xff0c;数据线&#xff08;SDA&…

Docker镜像列表中的none:none是什么

在构建过Docker镜像的电脑上查看本地镜像列表&#xff0c;有可能看到下图红框中的镜像&#xff0c;在列表中展示为<none>:<none>&#xff1a; 这种镜像在Docker官方文档中被称作dangling images&#xff0c;指的是没有标签并且没有被容器使用的镜像。 官方解释 …

三、JVM监控及诊断工具-GUI篇

目录 一、工具概述二、jconsole&#xff08;了解即可&#xff09;1、基本概述2、启动3、三种连接方式4、作用 三、Visual VM 一、工具概述 二、jconsole&#xff08;了解即可&#xff09; 1、基本概述 从Java5开始&#xff0c;在JDK中自带的Java监控和管理控制台用于对JVM中内…

系统架构设计高级技能 · Web架构

现在的一切都是为将来的梦想编织翅膀&#xff0c;让梦想在现实中展翅高飞。 Now everything is for the future of dream weaving wings, let the dream fly in reality. 点击进入系列文章目录 系统架构设计高级技能 Web架构 一、Web架构介绍1.1 Web架构涉及技术1.2 单台服务…

计算机组成原理 | 第一章 计算机系统概述

目录 计算机发展历程 计算机系统层次结构 计算机的性能指标 计算机发展历程 电子计算机的发展已经历了4代&#xff0c;这4代计算机的主要元件分别是电子管、晶体管、中小规模集成电路、大规模集成电路。微型计算机的发展以微处理器技术为标志。可以在计算机中直接执行的语…

快到家了【经济学人】

Refugees Almost home China has successfully absorbed many refugees from Vietnam. But it is ill-prepared for another influx Oct 10th 2015 | QIAOGANG, GUANGXI PROVINCE | From the print edition 来源&#xff1a;Economist 翻译&#xff1a;Z.K. IN A restaurant…

军事物联网如何改变未来战争模式?

军事物联网如何改变未来战争模式&#xff1f; 2017-05-08 17:45:17.0 你是否听说&#xff0c;在物联网的世界里&#xff0c;每一粒沙子都将拥有自己的IP地址。 互联网为我们创造了虚拟世界&#xff0c;与其一字之差的物联网&#xff0c;却为我们开辟了一个从虚拟转向现实的窗口…

去越南旅游,2万人民币能承担几天的花销?

2万人民币可以兑换6600多万越南盾,三年前我有一个同学带着一万块人民币,当时在越南生活了差不多三个月的时间。他之所以会去越南,主要是当时听人家说在越南农村好找老婆,并且彩礼会非常的少,所以就带着一万块钱先去看一看。虽然人回来的时候瘦了点黑了点,但是三个多月只花…

基于springboot学生社团管理系统/基于Java的高校社团管理系统的设计与实现

摘 要 随着信息技术和网络技术的飞速发展&#xff0c;人类已进入全新信息化时代&#xff0c;传统管理技术已无法高效&#xff0c;便捷地管理信息。为了迎合时代需求&#xff0c;优化管理效率&#xff0c;各种各样的管理系统应运而生&#xff0c;各行各业相继进入信息管理时代&…

QChart——折线

Qchart的图形显示依附于QChartView&#xff0c;创建一个QChartView继承类&#xff0c;通过窗口部件的提升进行图表的显示 一、简单认识QLineSeries QLineSeries属于折线类&#xff0c;它继承于QXYSeries类&#xff0c;可以使用QXYSeries类所有方法&#xff0c;对折线进行属性设…

前端需要理解的性能优化知识

优化的目的是展示更快、交互响应快、页面无卡顿情况。 1 性能指标 2 分析方法 使用 ChromeDevTool 作为性能分析工具来观察页面性能情况。其中Network观察网络资源加载耗时及顺序&#xff0c;Performace观察页面渲染表现及JS执行情况&#xff0c;Lighthouse对网站进行整体评分…

基于android的学生公寓后勤系统/学生公寓管理系统APP

摘 要 随着网络科技的发展&#xff0c;移动智能终端逐渐走进人们的视线&#xff0c;相关应用越来越广泛&#xff0c;并在人们的日常生活中扮演着越来越重要的角色。因此&#xff0c;关键应用程序的开发成为影响移动智能终端普及的重要因素&#xff0c;设计并开发实用、方便的应…

PCB设计常见问题

Fill Mode中存在3个选项 Solid&#xff08;Copper Regions&#xff09; Hatched&#xff08;Tracks/arcs&#xff09; None&#xff08;outlines&#xff09; 区别Solid&#xff08;Copper Regions&#xff09;过大电流的能力更强&#xff0c;且对于电路板存在的分布电容的干扰…

第三张鼠标键盘的高效使用

引言: 对于键盘的熟练使用更是一个网络时的基本技能所有要成为一个好的网络工程师我们应该熟练键盘操作已经能熟练的使用一些常用软件。––键盘和鼠标。速速度的唯一途径就是多演戏打字速快对今后的学习是有好处的。 一 鼠标和键盘 键盘和鼠标是两种常用的输入设备。 (一…

鼠标跟随的实现

鼠标跟随主要根据X,Y轴来计算 主要代码函数是 span[0].style.left event.clientX “px”; 计算X轴 span[0].style.top event.clientY “px”; 计算Y轴 <!DOCTYPE html> <html><head><meta charset"UTF-8"><title></title>&…

虚拟机Ubuntu内鼠标闪烁终极解决方案

话说这个问题很早就遇到了&#xff0c;最近才解决&#xff0c;不免唏嘘。 由于造成鼠标闪烁的原因有很多&#xff0c;鼠标闪烁的特点也有很多&#xff0c;因此网上也充斥着很多解决方案&#xff0c;这里一并做一下梳理&#xff0c;以节约各位看众时间。 1.通用解决方法 这个方…

数据结构--树4.2.1(二叉树)

目录 一、二叉树的存储结构 二、二叉树的遍历 一、二叉树的存储结构 顺序存储结构&#xff1a;二叉树的顺序存储结构就是用一维数组存储二叉树中的各个结点&#xff0c;并且结点的存储位置能体现结点之间的逻辑关系。 链式存储结构&#xff1a;二叉树每个结点最多只有两个孩…

手把手带你学python自动化测试(五)——鼠标键盘操作

在浏览器中&#xff0c;通常会用到鼠标来进行操作&#xff0c;比如右键菜单中选择一个操作&#xff0c;在 selenium 中提供了下列鼠标相关操作。 ActionChains 类似提供了以下方法&#xff1a; context_click() 右击 double_click() 双击 drag_and_drop() 拖拽 鼠标右击 …

7,鼠标学习二

《鼠标学习一》描述的是鼠标在客户区情况下&#xff0c; 当鼠标在非客户区的时候呢&#xff1f; 窗口的非客户区包括&#xff1a;标题栏&#xff0c;菜单和窗口滚动条&#xff0c;系统一般不需要用户处理非客户区消息&#xff0c;只要将其发送个DefWindowProc即可&#xff0c…

Scractch3.0_Arduino_ESP32_图形化编程学习_蓝牙鼠标(四)

蓝牙鼠标 目的器材程序联系我们 目的 通过C02实现蓝牙鼠标。 器材 硬件: 齐护机器人C02 购买地址 软件:scratch3.0 下载地址:官网下载 程序 蓝牙鼠标使用使用ESP32自带的BLE蓝牙&#xff0c;不需要再外接模块。可以实现鼠标移动&#xff0c;左右键的点击动作。 联系我们…