多线程(33)ConcurrentHashMap

ConcurrentHashMap 是 Java 并发包中提供的一个线程安全的哈希表实现。与传统的同步容器相比,ConcurrentHashMap 通过一种分段锁的机制实现了更高的并发度。本节将深入探讨其设计原理,结合源码进行分析,并通过代码示例来演示其使用方法。

设计原理

ConcurrentHashMap 的设计理念是将整个哈希表分为若干个段(Segment),每个段都是一个独立的哈希表,并且拥有自己的锁。当进行插入、删除、更新等操作时,只需要锁定对应的段,而不是整个哈希表。这样,当多线程访问不同段的数据时,这些操作就可以完全并行执行,大大提升了并发性能。

结构解析

在 Java 8 之前,ConcurrentHashMap 的内部实际上是由 Segment 数组组成的,每个 Segment 管理着一定范围的哈希桶。每个 Segment 继承自 ReentrantLock,可以独立加锁。在 Java 8 及以后的版本中,ConcurrentHashMap 放弃了 Segment 的设计,改为直接使用 Node 数组加链表和红黑树,但仍然保持了并发访问的能力,主要是通过使用了 CAS 操作和 synchronized 同步块来实现。

java 复制代码
// ConcurrentHashMap 源码片段(简化版本,基于 Java 8+)
class ConcurrentHashMap<K,V> extends AbstractMap<K,V> implements ConcurrentMap<K,V> {
    transient volatile Node<K,V>[] table;

    static final class Node<K,V> implements Map.Entry<K,V> {
        final int hash;
        final K key;
        volatile V value;
        volatile Node<K,V> next;

        Node(int hash, K key, V value, Node<K,V> next) {
            this.hash = hash;
            this.key = key;
            this.value = value;
            this.next = next;
        }

        public final K getKey()       { return key; }
        public final V getValue()     { return value; }
        public final int hashCode()   { return key.hashCode() ^ value.hashCode(); }
    }
}

操作细节

  • put操作:当插入一个键值对时,首先计算键的哈希值来确定其在表中的位置。如果目标位置还没有节点,它就使用 CAS 操作直接插入。如果目标位置已经有节点了,则锁定该节点,进而更新数据。
  • get操作:读操作一般不需要加锁(在 Java 8 以后),因为节点的 value 是用 volatile 关键字声明的,可以保证可见性。如果在查询过程中遇到了链表或红黑树,就顺着链表或树进行搜索。

代码演示

java 复制代码
import java.util.concurrent.ConcurrentHashMap;

public class ConcurrentHashMapExample {
    public static void main(String[] args) {
        ConcurrentHashMap<String, String> map = new ConcurrentHashMap<>();

        // 示例:并发插入
        Thread thread1 = new Thread(() -> map.put("key1", "value1"));
        Thread thread2 = new Thread(() -> map.put("key2", "value2"));

        thread1.start();
        thread2.start();

        // 等待线程结束
        try {
            thread1.join();
            thread2.join();
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
        }

        // 获取并打印结果
        System.out.println(map);
    }
}

总结

ConcurrentHashMap 采用了分段锁的设计理念,大大提升了并发性能,在多线程环境下提供了线程安全的哈希表实现。随着 Java 版本的更新,其内部实现有所变化,但目标仍然是为了提供高效的并发访问。正确使用 ConcurrentHashMap 可以帮助开发者构建高性能的并发应用。

相关推荐
thinktik4 小时前
AWS EKS安装S3 CSI插件[AWS 海外区]
后端·kubernetes·aws
Tony Bai6 小时前
【Go 网络编程全解】12 本地高速公路:Unix 域套接字与网络设备信息
开发语言·网络·后端·golang·unix
Yeats_Liao7 小时前
Go Web 编程快速入门 06 - 响应 ResponseWriter:状态码与头部
开发语言·后端·golang
mit6.8247 小时前
[Agent可视化] 编排工作流(Go) | Temporal引擎 | DAG调度器 | ReAct模式实现
开发语言·后端·golang
猪哥-嵌入式9 小时前
Go语言实战教学:从一个混合定时任务调度器(Crontab)深入理解Go的并发、接口与工程哲学
开发语言·后端·golang
thinktik9 小时前
AWS EKS 计算资源自动扩缩之Fargate[AWS 海外区]
后端·kubernetes·aws
不爱编程的小九九9 小时前
小九源码-springboot099-基于Springboot的本科实践教学管理系统
java·spring boot·后端
lang201509289 小时前
Spring Boot集成Spring Integration全解析
spring boot·后端·spring
雨夜之寂9 小时前
第一章-第二节-Cursor IDE与MCP集成.md
java·后端·架构
大G的笔记本10 小时前
Spring IOC和AOP
java·后端·spring