当前位置: 首页 > news >正文

什么类型的网站比较容易做北京网站空间域名

什么类型的网站比较容易做,北京网站空间域名,网站开发与建设方向,网页制作模板水果ConcurrentHashMap底层原理 ConcurrentHashMapJDK1.7底层结构线程安全底层具体实现 JDK1.8底层结构线程安全底层具体实现 总结JDK 1.7 和 JDK 1.8实现有什么不同?ConcurrentHashMap 中的 CAS 应用 ConcurrentHashMap ConcurrentHashMap 是一种线程安全的高效Map集合…

ConcurrentHashMap底层原理

  • ConcurrentHashMap
    • JDK1.7
      • 底层结构
      • 线程安全底层具体实现
    • JDK1.8
      • 底层结构
      • 线程安全底层具体实现
    • 总结
      • JDK 1.7 和 JDK 1.8实现有什么不同?
      • ConcurrentHashMap 中的 CAS 应用

ConcurrentHashMap

ConcurrentHashMap 是一种线程安全的高效Map集合

底层数据结构:

  • JDK1.7底层采用分段的数组+链表实现
  • JDK1.8 采用的数据结构跟HashMap1.8的结构一样,数组+链表/红黑二叉树。

JDK1.7

底层结构

image-20250128100021706

ConcurrentHashMap 是由 Segment 数组结构和 HashEntry 数组结构组成。

Segment 数组中的每个元素包含一个 HashEntry 数组,每个 HashEntry 数组属于链表结构。

线程安全底层具体实现

image-20250128101358835

首先将数据分为一段一段(这个“段”就是 Segment)的存储,然后给每一段数据配一把锁,当一个线程占用锁访问其中一个段数据时,其他段的数据也能被其他线程访问。

ConcurrentHashMap 是由 Segment 数组结构和 HashEntry 数组结构组成

Segment 继承了 ReentrantLock,所以 Segment 是一种可重入锁,扮演锁的角色。HashEntry 用于存储键值对数据。

static class Segment<K,V> extends ReentrantLock implements Serializable {
}

一个 ConcurrentHashMap 里包含一个 Segment 数组,Segment 的个数一旦初始化就不能改变Segment 数组的大小默认是 16,也就是说默认可以同时支持 16 个线程并发写。

Segment 的结构和 HashMap 类似,是一种数组和链表结构,一个 Segment 包含一个 HashEntry 数组,每个 HashEntry 是一个链表结构的元素,每个 Segment 守护着一个 HashEntry 数组里的元素,当对 HashEntry 数组的数据进行修改时,必须首先获得对应的 Segment 的锁。也就是说,对同一 Segment 的并发写入会被阻塞,不同 Segment 的写入是可以并发执行的。

JDK1.8

底层结构

image-20250128101023428

JDK1.8 的 ConcurrentHashMap 不再是 Segment 数组 + HashEntry 数组 + 链表,而是 Node 数组 + 链表 / 红黑树。不过,Node 只能用于链表的情况,红黑树的情况需要使用 TreeNode。当冲突链表达到一定长度时,链表会转换成红黑树。

线程安全底层具体实现

ConcurrentHashMap 取消了 Segment 分段锁,采用 Node + CAS + synchronized 来保证并发安全。数据结构跟 HashMap 1.8 的结构类似,数组+链表/红黑二叉树。Java 8 在链表长度超过一定阈值(8)时将链表(寻址时间复杂度为 O(N))转换为红黑树(寻址时间复杂度为 O(log(N)))。

Java 8 中,锁粒度更细,synchronized 只锁定当前链表或红黑二叉树的首节点,这样只要 hash 不冲突,就不会产生并发,就不会影响其他 Node 的读写,效率大幅提升。

底层源码:

image-20241223164349469

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;
}

工作步骤:

  1. 初始化,使用 cas 来保证并发安全,懒惰初始化 table
  2. 树化,当 table.length < 64 时,先尝试扩容,超过 64 时,并且 bin.length > 8 时,会将链表树化,树化过程会用 synchronized 锁住链表头
    说明:锁住某个槽位的对象头,是一种很好的细粒度的加锁方式,类似 MySQL 中的行锁
  3. put,如果该 bin 尚未创建,只需要使用 cas 创建 bin;如果已经有了,锁住链表头进行后续 put操作,元素添加至 bin 的尾部
  4. get,无锁操作仅需要保证可见性,扩容过程中 get 操作拿到的是 ForwardingNode 会让 get 操作在新 table 进行搜索
  5. 扩容,扩容时以 bin 为单位进行,需要对 bin 进行 synchronized,但这时其它竞争线程也不是无事可做,它们会帮助把其它 bin 进行扩容
  6. size,元素个数保存在 baseCount 中,并发时的个数变动保存在 CounterCell[] 当中,最后统计数量时累加

总结

JDK 1.7 和 JDK 1.8实现有什么不同?

  • 线程安全实现方式: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 数组的大小,并发度更大。

ConcurrentHashMap 中的 CAS 应用

ConcurrentHashMap 是 Java 中高效的并发集合类,它通过结合使用 CAS 和 synchronized 来保证线程安全性。

  • CAS:用于在没有锁的情况下保证单个桶(bucket)中的线程安全更新,尤其是 putIfAbsent()replace() 等操作。每个桶内部通常是通过 CAS 来完成插入、删除和更新操作,减少了全表锁定的情况,提高了性能。

    示例: 在 ConcurrentHashMapputIfAbsent 方法中,CAS 用来判断当前桶内是否已有值,如果没有,则将新值插入。

    void putIfAbsent(K key, V value) {int hash = hash(key);Node<K,V> node = table[hash & (table.length - 1)];// 使用 CAS 保证插入操作的线程安全if (node == null || cas(node, null, value)) {return value;}return null;
    }
    
  • synchronized:在一些较为复杂的操作(比如扩容、迭代器遍历时)中,仍然使用 synchronized 来保证线程安全。

通过这样的组合,ConcurrentHashMap 既能避免在并发情况下对整个数据结构加锁,提高效率,又能在需要的时候通过 synchronized 保证一致性。

http://www.yayakq.cn/news/336842/

相关文章:

  • 有哪个网站能卖自己做的衣服新动力网站建设
  • 专业设计网站效果保险网站建设公司
  • 深圳市龙华区住房和建设局网站制作网页无法铺平
  • 企业网站 免费移动互联网小程序开发
  • 聊城做wap网站哪儿好2020做seo还有出路吗
  • 保险网站有哪些如何进行网站推广
  • 员工入职 在哪个网站做招工网站备案信息被删除
  • 设计网站包含的功能模块WordPress文章图片采集插件
  • 做室内设计的网站有哪些方面建设银行国际互联网网站是什么
  • 网站开发与制作工资网站根目录怎么找
  • jsp网站开发书籍360元网站建设
  • WordPress富媒体说说分类信息网站如何优化
  • 福州房产网站建设如何用php做电商网站
  • 网站备案核验单怎么选返利网站开发文档
  • 陕西 餐饮 网站建设四川成都企业高端网站建设
  • 网站建设需要什么软件网站营销推广怎么做网络营销推广
  • 做关键字要改网站网站制作2007
  • 服装网站建设物流配送系统苏州归巢网络科技有限公司
  • 建立网站的流程是什么2个wordpress
  • 高端求职网站排名大连开发区网站
  • 做一个网站需要哪些步骤建设和管理环保网站
  • 做旅游网站公司临沂网站建设怎么样
  • seo网站推广seo微型购物网站建设模板
  • 上海网站建设公司推aspx怎么做网站
  • 手机网站建设广州招聘网站开发价格
  • 网站开发 技术投标重庆建设工程信息网官网入口30系统登入页面
  • 网站建设合同需要注意什么视频软件制作
  • 网站建设与管理试题答案贴心的合肥网站建设
  • 慈溪外贸公司网站html语言大型网站开发
  • 建站网站苏州零件加工网