首页 > 其他分享 >“码中谜“ ConcurrentHashMap线程安全机制的弹指一挥间

“码中谜“ ConcurrentHashMap线程安全机制的弹指一挥间

时间:2024-04-03 20:05:16浏览次数:20  
标签:Node ConcurrentHashMap 弹指一挥间 码中 value 线程 key 节点

引言:
ConcurrentHashMap是Java中解决并发编程问题的重要工具。它提供了线程安全的HashMap实现,并能在多线程环境下保持高性能。本文将深入ConcurrentHashMap的实现,解析其线程安全机制,并提供相关代码示例。

详解ConcurrentHashMap的数据结构:
ConcurrentHashMap在Java中是通过分离锁(Segment)来提供线程安全支持的散列表。在JDK 1.7及之前的版本中,ConcurrentHashMap内部是由一个Segment数组组成的,每个Segment是一个独立的哈希表,拥有自己的锁。在JDK 1.8中,已经废弃了Segment的设计,取而代之的是使用了Node数组加链表或红黑树,并引入了首节点加锁策略,减少了锁的粒度,优化了性能。

代码示例:

class ConcurrentHashMap<K,V> extends AbstractMap<K,V> implements ConcurrentMap<K,V>, Serializable {
    transient volatile Node<K,V>[] table;
    
    // JDK 1.8中Node的定义
    static class Node<K,V> implements Map.Entry<K,V> {
        final int hash; // 节点的哈希值
        final K key; // 键
        volatile V value; // 值,使用volatile关键字保证线程安全性
        volatile Node<K,V> next; // 下一个节点,使用volatile关键字保证线程安全性

        Node(int hash, K key, V value, Node<K,V> next) {
            this.hash = hash;
            this.key = key;
            this.value = value;
            this.next = next;
        }
        // 其他忽略的方法...
    }
    // 其他忽略的方法和细节...
}

线程安全性的关键机制:

  • volatile关键字确保节点值对所有线程立即可见。
  • 使用synchronized同步关键段代码,并在JDK 1.8中使用首节点加锁而不是分段锁,简化了实现。
  • CAS无锁操作确保put等方法能够原子性地完成。

JDK 1.8中的改进:

  • 移除了Segment分段锁,采用首节点加锁的方式,减少锁的粒度和提升访问效率。
  • sizeCtl变量控制节点容量和数组扩容,优化大量并发操作下的性能。

图解代码示例:
如同您看到的插图所示,多个线程能够操作数组的不同部分而不互相干扰,是因为在最新的版本中,它们通过使用锁(在JDK 1.8中是使用节点的内部锁)来确保对于任意单个bucket,一次只能有一个线程在写入。每个线程操作自己负责的那一部分的数组段(bucket),从而避免了线程间的冲突。当一个线程需要写入或更新时,它将锁定对应的bucket,这样其他线程就无法同时对该bucket进行写入或更新,保证了操作的线程安全性。

// JDK 1.8 ConcurrentHashMap的插入或更新操作简化示例
public V put(K key, V value) {
    return putVal(hash(key), key, value, false, true);
}

final V putVal(int hash, K key, V value, boolean onlyIfAbsent, boolean evict) {
    if (key == null || value == null) throw new NullPointerException();
    int n; Node<K,V>[] tab;
    // 其他代码省略...
    if ((tab = table) != null && (n = tab.length) > 0) {
        int i = (n - 1) & hash; // 定位到具体的bucket索引
        Node<K,V> f = tabAt(tab, i); // 使用tabAt()安全地读取第一个节点
        // 锁定bucket首节点进行操作...
        synchronized (f) {
            // 进行节点插入或更新操作
            // 具体操作代码省略
        }
    }
    // 其他代码省略...
}

在实际的ConcurrentHashMap中,这一复杂过程涉及许多其他的并发控制技巧和优化措施,确保性能在维护线程安全的同时保持高效。希望上述代码示例和解释能帮助您更清楚地理解ConcurrentHashMap是如何实现线程安全操作的。上述代码示例的意图是提供一个简化的视角,来帮助理解ConcurrentHashMap的原理和实现方式。

自定义同步策略:
展示如何通过继承ConcurrentHashMap来实现自定义的线程安全策略来满足特定需求。

深入JVM层面:
详述ConcurrentHashMap是如何与JVM协同工作,借助JVM的内存模型和线程调度机制来实现线程安全性。

实践案例分析:
通过真实的使用场景,分析正确使用ConcurrentHashMap可以如何提升软件系统的并发处理能力和性能。

结论:
总结ConcurrentHashMap的优点,在并发环境中相比其他Map实现的高性能优势,并提供最佳实践指南。

以上结构可作为撰写文章的模板与指导,并在具体编写时添加相关代码示例和图解,使内容更加丰富和易于理解。

标签:Node,ConcurrentHashMap,弹指一挥间,码中,value,线程,key,节点
From: https://blog.csdn.net/m0_52172586/article/details/137346491

相关文章

  • 从bootstrap源码中学习Sass(一)
    可以在github看代码,非常方便:https://github.com/twbs/bootstrap/blob/main/scss/_variables.scss就是有时候网络差。基础用法scss/bootstrap.scss1.@import、@include、@mixin//引入`variables.scss`@importvariables;//调用`@mixin`创建的sass代码块//在调用前必须......
  • 【JavaParser笔记02】JavaParser解析Java源代码中的类字段信息(javadoc注释、字段​​
    这篇文章,主要介绍如何使用JavaParser解析Java源代码中的类字段信息(javadoc注释、字段名称)。目录一、JavaParser依赖库1.1、引入依赖1.2、获取类成员信息(1)案例代码<......
  • 如何在 Laravel 代码中正确地使用数据库事务
    如何在Laravel代码中正确地使用数据库事务22594英文原文 /  翻译 /  1852 /  4 / 创建于 2年前 /  1个改进 引言在web开发中,数据的完整性和准确性非常重要。因此,必须确保我们编写的代码能够以安全的方式存储、更新和删除数据库中的数据。在本文......
  • Collections工具类,可以使用collections工具类对代码中的list进行分组
    /***根据活动id进行分组*key活动id*value活动id对应的商品id*/Map<Long,Set<Long>>collect=activitySkuList.stream().collect(Collectors.groupingBy(ActivitySku::getActivityId......
  • ConcurrentHashMap底层详解
    ConcurrentHashMap是线程安全且高效的HashMap。一、使用原因在并发编程中使用HashMap可能导致程序死循环。而使用线程安全的HashTable效率又非常低下,基于此产生了ConcurrentHashMap。1.线程不安全的HashMap在多线程环境下,使用HashMap进行put操作会引起死循环,导致CPU利用率......
  • python连接clickhouse-当密码中存在特殊字符比如@时处理方法
    我是使用clickhouse_sqlalchemy库来使用clickhous的。我的密码是:'Lovedan@971220'连接clickhous执行sql语句时候,会报错认证失败:Origexception:Code:516,e.displayText()=DB::Exception:default:Authenticationfailed:passwordisincorrectorthereisnouserwith......
  • shell代码中各种判断方式
    if[-n"$line"];then//判断字符串是否为空,一定要有双引号if["$PIDS"!=""];then//判断字符串是否为空,一定要有双引号if[-f$file];then//判断是否是目录newfile="${file//查询的字符串/替换的字符串}”//字符串替换if[[-f$sourceFile]]&&[[${sourceFi......
  • JAVA系统源码中的AI智能绘画生成技术揭秘
    在数字化时代,人工智能(AI)已经逐渐渗透到我们生活的方方面面,从智能语音助手到自动驾驶汽车,无不体现出AI技术的强大魅力。而在艺术领域,AI同样展现出了惊人的创造力。近期,一项融入JAVA系统源码的AI智能绘画生成技术引起了广泛关注。这项技术究竟有何神奇之处?让我们一起来揭秘。一......
  • RocketMQ为什么这么快?我从源码中扒出了10大原因!
    大家好,我是三友~~RocketMQ作为阿里开源的消息中间件,深受广大开发者的喜爱而这其中一个很重要原因就是,它处理消息和拉取消息的速度非常快那么,问题来了,RocketMQ为什么这么快呢?接下来,我将从以下10个方面来探讨一下RocketMQ这么快的背后原因如果你对RocketMQ还不了解,可以从公众......
  • RocketMQ为什么这么快?我从源码中扒出了10个原因!
    大家好,我是三友~~RocketMQ作为阿里开源的消息中间件,深受广大开发者的喜爱而这其中一个很重要原因就是,它处理消息和拉取消息的速度非常快那么,问题来了,RocketMQ为什么这么快呢?接下来,我将从以下10个方面来探讨一下RocketMQ这么快的背后原因如果你对RocketMQ还不了解,可以从公众......