我有一个嵌套地图的例子如下:
private final static Map<String, TreeMap<Long,String>> outerConcurrentMap = new ConcurrentHashMap<>();
我知道ConcurrentHashMap
是线程安全的,但是我想了解这个CHM控件的TreeMap
,它们在CHM中是否也是线程安全的?
我正在进行的操作是:
get(K)
从CHM检索TreeMap。tailMap(K,boolean)
方法从TreeMap中检索数据。clear()
CHM。在这种情况下我想要一个线程安全的结构。上面的实现是否是线程安全的?如果没有,请提出解决方案。
答案 0 :(得分:4)
一旦完成TreeMap<?, ?> tm = chm.get(key);
,您就不再处于线程安全领域。特别是,如果另一个线程更新树形图(通过CHM或不更新),您可能会看到或可能看不到更改。更糟糕的是,您在tm
中的地图副本可能已损坏......
一种选择是使用线程安全映射,例如ConcurrentSkipListMap。
答案 1 :(得分:2)
简单回答:不。
如果您的地图是ConcurrentHashMap,那么影响您的hashmap状态的所有操作都是线程安全的。 根本不是意味着存储在该地图中的对象变得线程安全。
如何运作;你创建任何类型的对象,并通过将其添加到这样的地图,对象本身变得线程安全吗?当你从地图中删除该对象时,&#34;线程 - 不安全&#34;恢复了吗?!
答案 2 :(得分:2)
假设您在多个线程中执行所有这些操作,不,它不是线程安全的。
忽略您通过TreeMap
访问 ConcurrentHashMap
的事实 - 您最终会同时访问TreeMap
多个线程,包括其中一个或多个写入地图。这不安全,因为TreeMap
对于这种情况不是线程安全的:
请注意,此实现未同步。如果多个线程同时访问映射,并且至少有一个线程在结构上修改了映射,则必须在外部进行同步。
答案 3 :(得分:1)
有些场景是线程安全的,有些则不是:
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
慢,但其内部结构不需要在访问期间锁定完整集合,从而使其在并发环境中有效。
答案 4 :(得分:0)
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);
}