ConcurrentHashMap 线程内的 Treemap 是否安全?

is Treemap inside ConcurrentHashMap thread safe?

我有一个嵌套地图的情况如下:

private final static Map<String, TreeMap<Long,String>> outerConcurrentMap = new ConcurrentHashMap<>();

我知道 ConcurrentHashMap 是线程安全的,但我想知道 TreeMap 持有的这个 CHM,它们在 CHM 中也是线程安全的吗?

我做的操作是:

  1. 如果未找到特定键 --> 创建新的 TreeMap 并放置在键上。
  2. 如果找到键,则获取 TreeMap 并更新它。
  3. 使用 get(K) 从 CHM 检索 TreeMap。
  4. 使用 tailMap(K,boolean) 方法从 TreeMap 中检索数据。
  5. clear() CHM.

在这种情况下我想要一个线程安全的结构。上面的实现是否线程安全?如果没有,请提出解决方案。

简单的回答:没有。

如果您的映射是 ConcurrentHashMap,那么所有影响您的哈希映射状态的操作 都是线程安全的。这确实 一点也不 意味着存储在该映射中的对象成为线程安全的。

那将如何运作;您创建任何类型的对象,并通过将其添加到这样的映射中,该对象本身就变得线程安全了?当您从地图中删除该对象时,"thread-unsafety" 会恢复吗?!

假设您在多个线程中执行所有这些操作,不,这不是线程安全的。

忽略您已经通过 ConcurrentHashMap 访问 TreeMap 的事实 - 您最终会有多个线程访问 TreeMap同时,包括其中一个或多个写入地图。这不安全,因为 TreeMap 在这种情况下不是线程安全的:

Note that this implementation is not synchronized. If multiple threads access a map concurrently, and at least one of the threads modifies the map structurally, it must be synchronized externally.

完成后 TreeMap<?, ?> tm = chm.get(key); 您不再处于线程安全区域。特别是,如果另一个线程更新树状图(通过或不通过 CHM),您可能会或可能不会看到更改。更糟糕的是,您在 tm 中的地图副本可能已损坏...

一种选择是使用线程安全映射,例如 ConcurrentSkipListMap。

有些场景是线程安全的,有些不是:

1. 是的,这是线程安全的,但在您将其放入 CHM 之前,其他线程无法看到新创建的 TreeMap。但这应该小心实施以避免竞争条件——你应该确保检查和插入是自动执行的:

// create an empty treemap somewhere before
TreeMap<Long, String> emptyMap = new TreeMap<>();
...
// On access, use putIfAbsent method to make sure that if 2 threads  
// try to get same key without associated value sumultaneously,
// the same empty map is returned  
if (outerConcurrentMap.putIfAbsent(key, emptyMap) == null) {
    emptyMap = new TreeMap<>();
};
map = outerConcurrentMap.get(key);

2, 3, 4. 不行,你首先需要通过显式锁或者使用synchronized来锁定这个TreeMap。 TreeMap自己没有同步

5. 是的,这个操作是在CHM上进行的,所以是线程安全的。

如果您需要完全线程安全的排序映射,请改用 ConcurrentSkipListMap。它比 TreeMap 慢,但其内部结构在访问期间不需要锁定完整集合,因此在并发环境中有效。

TreeMap 本身不应该是线程安全的。因为只有 ConcurrentHashMap 的方法有效。

您可以做的是:

private final static Map<String, SortedMap <Long,String>> outerConcurrentMap= new ConcurrentHashMap<String, SortedMap <Long,String> >();

static {
    // Just an example
    SortedMap map = Collections.synchronizedSortedMap(new TreeMap(...));
    outerConcurrentMap.put("...",map);
}