当提供线程安全映射时,Guava'} Tables.newCustomTable(Map, Supplier)方法会返回线程安全表吗?例如:
public static <R, C, V> Table<R, C, V> newConcurrentTable() {
return Tables.newCustomTable(
new ConcurrentHashMap<R, Map<C, V>>(),
new Supplier<Map<C, V>>() {
public Map<C, V> get() {
return new ConcurrentHashMap<C, V>();
}
});
}
该代码是否实际返回并发表?
答案 0 :(得分:21)
来自doc:“如果多个线程同时访问此表并且其中一个线程修改了表,则必须在外部进行同步。”
并发支持集合是不够的。
答案 1 :(得分:17)
Kevin Bourrillion是对的。您构建的映射不是线程安全的技术原因是,即使您使用的映射是线程安全的,表操作也可能不是。让我举一个放置的示例,在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);
}
在处理map == null
案件时,线程安全受到影响。也就是说,两个或多个线程可以进入该块并为columnKey
创建一个新条目,最后一个执行backingMap.put(rowKey, map)
将最终覆盖columnKey
中backingMap
的条目。 1}},这会导致其他线程执行的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
或{{1 }}