ConcurrentHashMap 线程内的 Treemap 是否安全?
is Treemap inside ConcurrentHashMap thread safe?
我有一个嵌套地图的情况如下:
private final static Map<String, TreeMap<Long,String>> outerConcurrentMap = new ConcurrentHashMap<>();
我知道 ConcurrentHashMap
是线程安全的,但我想知道 TreeMap
持有的这个 CHM,它们在 CHM 中也是线程安全的吗?
我做的操作是:
- 如果未找到特定键 --> 创建新的 TreeMap 并放置在键上。
- 如果找到键,则获取 TreeMap 并更新它。
- 使用
get(K)
从 CHM 检索 TreeMap。
- 使用
tailMap(K,boolean)
方法从 TreeMap 中检索数据。
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);
}
我有一个嵌套地图的情况如下:
private final static Map<String, TreeMap<Long,String>> outerConcurrentMap = new ConcurrentHashMap<>();
我知道 ConcurrentHashMap
是线程安全的,但我想知道 TreeMap
持有的这个 CHM,它们在 CHM 中也是线程安全的吗?
我做的操作是:
- 如果未找到特定键 --> 创建新的 TreeMap 并放置在键上。
- 如果找到键,则获取 TreeMap 并更新它。
- 使用
get(K)
从 CHM 检索 TreeMap。 - 使用
tailMap(K,boolean)
方法从 TreeMap 中检索数据。 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);
}