Java17中ConcurrentHashMap类介绍、应用场景和示例代码

概述

ConcurrentHashMap 是 Java 并发集合框架中基于分段锁(Java 7)或 CAS + synchronized 分段优化(Java 8+)实现的高并发线程安全哈希表,适用于高并发场景下的键值存储。它通过细粒度锁和原子操作,在保证线程安全的同时提供高性能的并发读写能力。


一、核心特性
  1. 线程安全:支持多线程并发读写,无需外部同步。
  2. 分段锁优化​(Java 8+):
    • 使用 Node + synchronized 锁单个桶(链表或红黑树),而非全局锁。
    • 通过 CAS(Compare-And-Swap)实现无锁化的插入和扩容。
  3. 原子性方法:支持 computeIfAbsentmerge 等原子操作,避免竞态条件。
  4. 弱一致性迭代器:遍历时反映创建迭代器后的部分修改(不保证实时一致性)。
  5. 高并发性能:读操作完全无锁,写操作锁粒度细化到单个桶。
  6. 空值限制:​不允许 null 键或值​(防止并发场景下的歧义)。
  7. 兼容性:支持 Java 17 的模块化系统(JPMS)。

二、与 HashMap、Hashtable 的对比
特性ConcurrentHashMapHashtableHashMap
线程安全✅(分段锁/CAS优化)✅(全表锁)
性能高并发下性能优低(全局锁阻塞)单线程下最高
空值支持
迭代器一致性弱一致性强一致性(全锁遍历)快速失败(Fail-Fast)

三、应用场景
  1. 高并发缓存:如缓存用户会话、商品信息。
  2. 计数器:实时统计(如点击量、在线人数)。
  3. 实时数据处理:多线程写入并聚合结果(如日志分析)。
  4. 替代 synchronizedMap:需要高性能且线程安全的键值存储。
  5. 分布式系统本地存储:在单机多线程环境下替代分布式缓存。

四、示例代码
1. 基本操作(线程安全插入与遍历)
import java.util.concurrent.ConcurrentHashMap;

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

        // 多线程并发插入
        Runnable task = () -> {
            for (int i = 0; i < 1000; i++) {
                map.put(Thread.currentThread().getName() + "-" + i, i);
            }
        };

        Thread t1 = new Thread(task);
        Thread t2 = new Thread(task);
        t1.start();
        t2.start();
        t1.join();
        t2.join();

        System.out.println("Map大小: " + map.size()); // 2000(无重复键)
    }
}
2. 原子操作(避免竞态条件)
// 统计单词频率(线程安全)
ConcurrentHashMap<String, Integer> wordCount = new ConcurrentHashMap<>();
List<String> words = List.of("apple", "banana", "apple", "orange", "banana");

words.parallelStream().forEach(word -> {
    // 原子性更新:若键不存在则初始化为1,否则递增
    wordCount.compute(word, (k, v) -> (v == null) ? 1 : v + 1);
});

System.out.println(wordCount); // {orange=1, banana=2, apple=2}
3. 合并与替换(原子方法)
ConcurrentHashMap<String, Integer> scores = new ConcurrentHashMap<>();
scores.put("Alice", 90);

// 合并操作(原子性)
scores.merge("Alice", 10, (oldVal, delta) -> oldVal + delta); // Alice: 100
scores.merge("Bob", 80, (oldVal, delta) -> oldVal + delta);   // Bob: 80(自动插入)

// 替换操作(原子性)
scores.replace("Alice", 100, 95); // 仅当当前值为100时替换为95
4. 批量方法(Java 8+)
// 并行搜索(查找第一个值大于50的键)
String resultKey = scores.search(1, (k, v) -> v > 50 ? k : null);
System.out.println("找到的键: " + resultKey); // 如 "Alice"

// 并行遍历(线程安全)
scores.forEach(2, (k, v) -> System.out.println(k + ": " + v));

// 归约计算(求和)
int sum = scores.reduce(2, (k, v) -> v, Integer::sum);
System.out.println("总分: " + sum);
5. 实现 LRU 缓存(线程安全)
public class ConcurrentLRUCache<K, V> {
    private final ConcurrentHashMap<K, V> cache;
    private final ConcurrentLinkedQueue<K> queue;
    private final int maxSize;

    public ConcurrentLRUCache(int maxSize) {
        this.maxSize = maxSize;
        this.cache = new ConcurrentHashMap<>(maxSize);
        this.queue = new ConcurrentLinkedQueue<>();
    }

    public V get(K key) {
        V value = cache.get(key);
        if (value != null) {
            queue.remove(key); // 需优化为 O(1) 操作(实际生产环境建议用自定义数据结构)
            queue.add(key);
        }
        return value;
    }

    public void put(K key, V value) {
        if (cache.size() >= maxSize) {
            K oldest = queue.poll();
            if (oldest != null) {
                cache.remove(oldest);
            }
        }
        cache.put(key, value);
        queue.add(key);
    }
}

五、注意事项

 1、​复合操作仍需同步
例如 if (map.containsKey(k)) map.put(k, v) 并非原子操作,应改用 computeIfAbsent

map.computeIfAbsent(k, key -> createExpensiveValue(key));

​2、避免在原子方法中阻塞
computemerge 等方法中的函数应尽量简短,避免长时间阻塞导致其他线程等待。

​3、扩容开销
并发扩容时可能短暂阻塞,初始化时可预估容量以减少扩容次数:

new ConcurrentHashMap<>(initialCapacity, 0.75f, concurrencyLevel);

4、迭代器弱一致性
遍历时可能不反映最新修改,需根据场景选择强一致性方案(如加锁)。

​5、替代方案
极端高并发场景下,可考虑 ConcurrentHashMap 的分段锁优化或分布式缓存(如 Redis)。


六、总结

在 Java 17 中,ConcurrentHashMap 是处理高并发键值存储的首选工具,其核心优势包括:

  • 分段锁优化:通过细粒度锁和 CAS 实现高并发性能。
  • 原子操作:简化线程安全的复合逻辑。
  • 批量方法:利用 searchforEachreduce 并行处理数据。

适用场景包括缓存、计数器、实时聚合等。结合 Java 17 的现代特性(如并行流),能高效解决多线程数据共享问题。需注意其弱一致性和复合操作陷阱,合理设计代码以确保线程安全与性能平衡。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值