You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Java中如何在put时阻塞ConcurrentHashMap的get操作且不锁住整张表

实现方案

核心思路

因为要求不对整张Map加synchronized锁,我们采用细粒度的锁控制实现需求,结合题目给定的「仅单线程更新」前提,不会出现多线程写冲突的问题,两种可选方案可以适配不同的业务场景:


方案一:Key级别的读写锁(性能最优,推荐)

仅对正在更新的key加锁,不影响其他key的正常读取,完全不会锁整张表:

  1. 额外维护一个锁容器,每个key对应独立的读写锁
  2. 读操作先拿对应key的读锁,读完成释放
  3. 写操作(put)先拿对应key的写锁,此时所有该key的读操作会被阻塞,直到写锁释放

完整代码实现

import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.locks.ReentrantReadWriteLock;

// 原有配置存储容器
ConcurrentHashMap<String, Config> configStore = new ConcurrentHashMap<>();
// 每个key对应独立的读写锁,实现细粒度控制
ConcurrentHashMap<String, ReentrantReadWriteLock> lockMap = new ConcurrentHashMap<>();

// 封装后的读操作
public Config getConfig(String configName) {
    // 不存在对应锁则自动初始化
    ReentrantReadWriteLock lock = lockMap.computeIfAbsent(configName, k -> new ReentrantReadWriteLock());
    lock.readLock().lock();
    try {
        return configStore.get(configName);
    } finally {
        lock.readLock().unlock();
    }
}

// 改造后的更新操作
void updateStore(String configName) {
    ReentrantReadWriteLock lock = lockMap.computeIfAbsent(configName, k -> new ReentrantReadWriteLock());
    lock.writeLock().lock();
    try {
        Config newConfig = generateNewConfig();
        Config oldConfig = configStore.get(configName);
        if (newConfig.replaces(oldConfig)) {
            configStore.put(configName, newConfig);
        }
    } finally {
        lock.writeLock().unlock();
    }
}

方案二:全局读写锁(实现简单,适配全局阻塞场景)

如果需求要求任意put操作执行时,所有key的读请求都要阻塞,可以用全局读写锁实现,同样不需要对整张Map加synchronized锁,读写锁的性能远优于粗粒度的synchronized锁:

import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.locks.ReentrantReadWriteLock;

ConcurrentHashMap<String, Config> configStore = new ConcurrentHashMap<>();
// 全局读写锁,读多写少场景性能优异
ReentrantReadWriteLock globalLock = new ReentrantReadWriteLock();

public Config getConfig(String configName) {
    globalLock.readLock().lock();
    try {
        return configStore.get(configName);
    } finally {
        globalLock.readLock().unlock();
    }
}

void updateStore(String configName) {
    globalLock.writeLock().lock();
    try {
        Config newConfig = generateNewConfig();
        Config oldConfig = configStore.get(configName);
        if (newConfig.replaces(oldConfig)) {
            configStore.put(configName, newConfig);
        }
    } finally {
        globalLock.writeLock().unlock();
    }
}

内容的提问来源于stack exchange,提问作者seriousgeek

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.06 16:18:01