Kevin Bourrillion是对的。您构建的映射不是线程安全的技术原因是,即使您使用的映射是线程安全的,表操作也可能不是线程安全的。让我举一个 put 的例子,如 中实现的那样,它由 :StandardTable
Tables.newCustomTable
public V put(R rowKey, C columnKey, V value) {
Map<C, V> map = backingMap.get(rowKey);
if (map == null) {
map = factory.get();
backingMap.put(rowKey, map);
}
return map.put(columnKey, value);
}
螺纹安全在处理外壳时受到损害。也就是说,两个或多个线程可以进入该块并为 创建一个新条目,而最后一个执行该条目最终将覆盖 in 中的条目,这将导致其他线程执行的操作丢失。特别是,在多线程环境中执行此操作的结果是非确定性的,这相当于说此操作不是线程安全的。map == null
columnKey
backingMap.put(rowKey, map)
columnKey
backingMap
put
此方法的正确实现是:
public V put(R rowKey, C columnKey, V value) {
ConcurrentMap<C, V> map = table.get(rowKey);
if (map == null) {
backingMap.putIfAbsent(rowKey, factory.get());
}
map = backingMap.get(rowKey);
return map.put(columnKey, value);
}
我目前正在调查是否有可能将实现与您想要执行的操作一起使用,以获得适当的线程安全 。ForwardingTable
ConcurrentTable
但说实话,我认为没有线程安全实现的原因是接口本身不提供任何并发构造,例如 或 .Table
putIfAbsent
replace