当Guava Table线程的支持映射是线程安全时,它是否安全?

Mic*_*son 16 java guava

当提供线程安全映射时, 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>();
        }
      });
}
Run Code Online (Sandbox Code Playgroud)

该代码是否实际返回并发表?

Kev*_*ion 21

从文档:"如果多个线程同时访问此表并且其中一个线程修改了表,则必须在外部进行同步."

并发支持集合是不够的.


vel*_*ist 18

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);
}
Run Code Online (Sandbox Code Playgroud)

在处理map == null外壳时,线程安全性受到影响.也就是说,两个或多个线程可能进入该块,并创建了一个新的条目columnKey,最后一个执行backingMap.put(rowKey, map)最终将覆盖为入门columnKeybackingMap,这将导致的损失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);
}
Run Code Online (Sandbox Code Playgroud)

我正在调查是否可以将ForwardingTable实现与您想要做的一起使用,以获得正确的线程安全ConcurrentTable.

但说实话,我认为没有线程安全实现的原因是Table接口本身不提供任何并发结构,例如putIfAbsentreplace.