如何在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




