网站的市场如何制作聊城做网站费用
2026/4/18 0:36:48 网站建设 项目流程
网站的市场如何制作,聊城做网站费用,wordpress 站群插件,wordpress主机配置摘要#xff1a;本篇围绕 Java 并发容器核心#xff0c;详细解析了 ConcurrentHashMap 在 JDK 1.7 和 JDK 1.8 版本中的实现原理与演进#xff0c;并对比了其与 HashMap、Hashtable 的核心差异。第6章 Java 并发容器6.1 ConcurrentHashMap的实现原理与使用6.1.1 为什么要使用…摘要本篇围绕 Java 并发容器核心详细解析了 ConcurrentHashMap 在 JDK 1.7 和 JDK 1.8 版本中的实现原理与演进并对比了其与 HashMap、Hashtable 的核心差异。第6章 Java 并发容器6.1 ConcurrentHashMap的实现原理与使用6.1.1 为什么要使用ConcurrentHashMapJDK1.7中的 HashMap 使用头插法插入元素在多线程的环境下扩容的时候有可能导致环形链表的出现形成死循环。因此JDK1.8使用尾插法插入元素在扩容时会保持链表元素原本的顺序不会出现环形链表问题。多线程同时执行 put 操作如果计算出来的索引位置是相同的那会造成前一个 key 被后一个 key 覆盖从而导致元素的丢失。此问题在JDK 1.7和 JDK 1.8 中都存在。常见的线程安全Map集合Hashtable是早期 Java 提供的线程安全的Map实现它的实现方式与HashMap类似但是在每个可能修改Hashtable状态的方法上加上synchronized关键字。ConcurrentHashMap在 JDK 1.8 以前采用了分段锁等技术来提高并发性能。在ConcurrentHashMap中将数据分成多个段Segment每个段都有自己的锁。在进行插入、删除等操作时只需要获取相应段的锁而不是整个Map的锁这样可以允许多个线程同时访问不同的段提高了并发访问的效率。在 JDK 1.8 以后是通过 volatile CAS 或者 synchronized 来保证线程安全的。6.1.2 ConcurrentHashMap 的结构ConcurrentHashMap是由Segment和HashEntry组成。 Segment是一种可重入锁ReentrantLock在ConcurrentHashMap里扮演锁的角色HashEntry则用于存储键值对数据。一个ConcurrentHashMap里包含一个Segment数组。Segment的结构和 HashMap类似是一种数组和链表结构。一个Segment里包含一个HashEntry数组每个HashEntry是一个链表结构的元素每个Segment守护着一个HashEntry数组里的元素当对HashEntry数组的数据进行修改时必须首先获得与它对应的Segment锁。这组图展示的是JDK 1.7 版本ConcurrentHashMap的核心设计它是为了解决HashMap线程不安全和Hashtable效率低下的问题而诞生的。分层结构与原理ConcurrentHashMap层顶层容器内部维护一个Segment数组相当于把整个哈希表拆分成了多个 小 HashMap。这种 分段锁 设计让不同 Segment 上的操作可以并发执行大大提升了并发效率。Segment 层分段锁实现Segment本身继承了ReentrantLock扮演锁的角色。每个Segment守护着一个HashEntry数组修改该数组中的元素前必须先获取对应的 Segment 锁。它的结构和HashMap类似也是数组 链表的结构。HashEntry 层数据存储单元用于存储具体的键值对Key-Value。每个HashEntry是链表结构的节点当发生哈希碰撞时会以链表形式追加在对应位置。通俗来讲ConcurrentHashMap 多个Segment组成的数组 | Segment HashEntry数组 ReentrantLock锁Segment HashEntry HashEntry ... | HashEntry(元素) key value next 指针 哈希值ConcurrentHashMap怎么实现的 ⭐JDK 1.7ConcurrentHashMapJDK 1.7 中 ConcurrentHashMap 的底层结构是Segment[]数组默认长度 16不可扩容 每个 Segment 内部的HashEntry[]数组 链表每个 Segment 继承自 ReentrantLock持有独立的分段锁相当于一个小 HashMapHashEntry[]数组各自管理一个 HashEntry [] 数组存储该分段下的键值对HashEntry 数组的每个元素是单向链表的头节点哈希冲突的键值对以链表形式存储在同一个桶中。JDK 1.8ConcurrentHashMap在 JDK 1.7 中ConcurrentHashMap 虽然是线程安全的但因为它的底层实现是数组 链表的形式所以在数据比较多的情况下访问是很慢的因为要遍历整个链表而 JDK 1.8 则使用了数组 链表/红黑树的方式优化了 ConcurrentHashMap 的实现具体实现结构如下JDK 1.8 ConcurrentHashMap JDK 1.8 ConcurrentHashMap 主要通过 volatile CAS 或者 synchronized 来实现的线程安全的。添加元素时首先会判断容器是否为空如果为空则使用volatile加CAS来初始化Node[]数组如果容器不为空定位元素位置并处理。分两种情况处理目标位置为空直接通过CAS操作将新节点放入该位置无需加锁高效。目标位置不为空存在哈希冲突已有链表或红黑树用synchronized 锁定该位置的头节点只锁链表 / 红黑树而非数组粒度更细。遍历该位置的链表 / 红黑树判断是否存在相同的键若存在则替换值否则新增节点。操作完成后判断链表长度是否超过阈值若超过则转为红黑树优化查询性能。如果把上面的执行用一句话归纳的话就相当于是ConcurrentHashMap通过对头结点加锁来保证线程安全的锁的粒度相比 Segment 来说更小了发生冲突和加锁的频率降低了操作性能提高。而且 JDK 1.8 使用的是红黑树优化了之前的固定链表那么当数据量比较大的时候查询性能也得到了很大的提升从之前的 O(n) 优化到了 O(logn) 的时间复杂度。ConcurrentHashMap用了悲观锁还是乐观锁?悲观锁和乐观锁都有用到。添加元素时首先会判断容器是否为空如果为空则使用 volatile 加 CAS 乐观锁 来初始化。如果容器不为空则根据存储的元素计算该位置是否为空。如果根据存储的元素计算结果为空则利用 CAS乐观锁 设置该节点如果根据存储的元素计算结果不为空则使用 synchronized悲观锁 然后遍历桶中的数据并替换或新增节点到桶中最后再判断是否需要转为红黑树这样就能保证并发访问时的线程安全了。恭喜你学习完本节内容✿

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询