You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

如何在ConcurrentHashMap中原子化存值?求兼容API16的替代方案

别担心,首次提问完全没问题,你的需求描述得特别清楚😊

你要实现的「key存在则返回对应value,不存在则创建新值关联后返回」的逻辑,用compute()确实很简洁,但它在Android API24才引入,没法在API16环境下使用。这里有两个线程安全的兼容方案,完全能满足你的需求:

方案1:直接用putIfAbsent() + get()组合

这是最直观的替代方式,利用putIfAbsent()的原子特性——仅当key不存在时才插入新值,返回null;若key已存在,则返回已有的value。结合get()做双重检查,就能完美实现需求:

Data data = mConcurrentHashMap.get("c:/directory/data");
if (data == null) {
    Data newData = new Data();
    // 尝试插入新值,若此时其他线程已插入同key的值,putIfAbsent会返回那个已存在的值
    data = mConcurrentHashMap.putIfAbsent("c:/directory/data", newData);
    // 如果返回null,说明我们成功插入了自己创建的新值
    if (data == null) {
        data = newData;
    }
}
// 最终data就是目标结果

为什么要做双重检查?
多线程场景下,当你get()null后,可能有其他线程先一步插入了该key的值,这时候putIfAbsent()会返回那个已存在的值,我们直接复用它,避免重复创建对象,同时保证线程安全。

方案2:封装成工具方法复用

如果这个逻辑需要在多处使用,建议封装成工具方法,提升代码复用性:

首先定义一个简单的工厂接口(兼容API16,不用Java8的Supplier):

public interface ValueFactory<V> {
    V create();
}

然后封装工具方法:

public static <K, V> V getOrCreate(ConcurrentHashMap<K, V> map, K key, ValueFactory<V> factory) {
    V value = map.get(key);
    if (value == null) {
        V newValue = factory.create();
        value = map.putIfAbsent(key, newValue);
        if (value == null) {
            value = newValue;
        }
    }
    return value;
}

使用时只需传入map、key和创建对象的逻辑:

Data data = getOrCreate(mConcurrentHashMap, "c:/directory/data", new ValueFactory<Data>() {
    @Override
    public Data create() {
        return new Data();
    }
});

这两个方案都基于ConcurrentHashMap本身的线程安全方法实现,和compute()的线程安全级别完全一致,而且完美兼容API16。

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

火山引擎 最新活动