多线程(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 可以帮助开发者构建高性能的并发应用。

相关推荐
嘉然今天吃粑粑柑几秒前
Kafka vs RabbitMQ:从消费模型到使用场景的一次讲清
后端
肥肥今天也好看1 分钟前
Java 日期格式化陷阱:YYYY vs yyyy 导致的生产事故分析
后端
用户948357016512 分钟前
可观测性落地:如何在 Java 项目中统一埋点 Trace ID?(一)
后端
天天摸鱼的java工程师2 分钟前
volatile 关键字底层原理:为什么它不能保证原子性?
java·后端
leikooo4 分钟前
SpringAI 多轮对话报错 400 Bad Request
后端·ai编程
小杨同学495 分钟前
C 语言实战:堆内存存储字符串 + 多种递归方案计算字符串长度
数据库·后端·算法
golang学习记6 分钟前
Go 中防止敏感数据意外泄露的几种姿势
后端
czlczl200209257 分钟前
Spring Boot 构建 SaaS 多租户架构
spring boot·后端·架构
小码编匠8 分钟前
完美替代 Navicat,一款开源免费、集成了 AIGC 能力的多数据库客户端工具!
数据库·后端·aigc
顺流8 分钟前
从零实现一个数据结构可视化调试器(一)
后端