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

如何线程安全地更新Guava LoadingCache中存储的Map对应字段值

解决方案

核心需要完成两处改造保证线程安全:

  • 替换缓存中存储的HashMap为线程安全的ConcurrentHashMap,同时修正CacheLoader的load方法返回可变的线程安全Map,避免不可变集合修改报错
  • 使用Guava Cache的asMap().compute()原子方法执行更新操作,避免「先get再put」的竞态条件

改造后完整代码

import com.google.common.cache.CacheBuilder;
import com.google.common.cache.CacheLoader;
import com.google.common.cache.LoadingCache;
import javax.annotation.Nonnull;
import java.util.concurrent.ConcurrentHashMap;
import java.util.Map;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;

public class TestCache {

    private LoadingCache<String, Map<String, String>> attemptsCache;

    public TestCache() {
        attemptsCache = CacheBuilder.newBuilder()
                .maximumSize(10000)
                .expireAfterWrite(1, TimeUnit.HOURS)
                .build(new CacheLoader<String, Map<String, String>>() {
                    @Override
                    public Map<String, String> load(@Nonnull final String key) {
                        // 返回线程安全的可变Map,替换原逻辑里不可变的Map.of()
                        return new ConcurrentHashMap<>();
                    }
                });
    }

    public void addCache(final String pathKey, final String inputKey, final String nameValue) throws ExecutionException {
        // 原初始写入逻辑可保留,也可以直接合并到下方compute逻辑实现首次写入+更新一体化
        Map<String, String> initMap = new ConcurrentHashMap<>();
        initMap.put("a", "1111");
        attemptsCache.put(pathKey, initMap);

        // 线程安全更新核心逻辑
        attemptsCache.asMap().compute(pathKey, (key, existingMap) -> {
            // 兜底兼容缓存key被过期淘汰的极端场景
            if (existingMap == null) {
                existingMap = new ConcurrentHashMap<>();
            }
            existingMap.put(inputKey, nameValue);
            return existingMap;
        });
    }
    
    public static void main(String[] args) throws ExecutionException {
        new TestCache().addCache("b","a","2222");
    }
}

实现逻辑说明

  1. 线程安全Map选型

普通HashMap不是线程安全实现,多线程并发修改时可能抛出ConcurrentModificationException,甚至破坏哈希表结构导致数据异常。ConcurrentHashMap采用CAS+细粒度锁实现并发安全,性能远高于Hashtable,完全适配缓存高频读写场景。

  1. 原子更新操作

直接调用attemptsCache.get(pathKey)读取Map后修改再存入的逻辑存在竞态:如果多个线程同时操作同一个缓存key,可能出现后写入的修改被覆盖的问题。LoadingCache的asMap()视图提供的compute方法是原子操作,同一时间只会有一个线程执行同一个key的计算逻辑,保证更新的原子性。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.01 17:39:04