Java ConcurrentHashMap中的Treemap是线程安全的吗?

Java ConcurrentHashMap中的Treemap是线程安全的吗?,java,concurrency,thread-safety,treemap,concurrenthashmap,Java,Concurrency,Thread Safety,Treemap,Concurrenthashmap,我有一个嵌套贴图的例子,如下所示: private final static Map<String, TreeMap<Long,String>> outerConcurrentMap = new ConcurrentHashMap<>(); private final static Map outerConcurrentMap=new ConcurrentHashMap(); 我知道ConcurrentHashMap是线程安全的,但是我想知道这个CHM中的

我有一个嵌套贴图的例子,如下所示:

private final static Map<String, TreeMap<Long,String>> outerConcurrentMap = new ConcurrentHashMap<>();
private final static Map outerConcurrentMap=new ConcurrentHashMap();
我知道
ConcurrentHashMap
是线程安全的,但是我想知道这个CHM中的
TreeMap
s,它们在CHM中也是线程安全的吗

我正在进行的操作包括:

  • 如果找不到特定的键-->创建新的树状图并放置在键上
  • 如果找到了键,则获取树映射并更新它
  • 使用
    get(K)
    从CHM检索树映射
  • 使用
    tailMap(K,布尔值)
    方法从树映射中检索数据
  • clear()
    CHM
  • 在这个场景中,我需要一个线程安全的结构。上述实现是否是线程安全的?如果没有,请提出解决方案。

    简单回答:没有

    如果您的映射是ConcurrentHashMap,那么影响hashmap状态的所有操作都是线程安全的。这并不意味着存储在地图中的对象是线程安全的

    这将如何运作;创建任何类型的对象,并将其添加到这样的映射中,对象本身就成为线程安全的?当你从地图上移除那个物体时,“线程不安全”就恢复了

    简单的回答是:不

    如果您的映射是ConcurrentHashMap,那么影响hashmap状态的所有操作都是线程安全的。这并不意味着存储在地图中的对象是线程安全的


    这将如何运作;创建任何类型的对象,并将其添加到这样的映射中,对象本身就成为线程安全的?当你从地图上移除那个物体时,“线程不安全”就恢复了

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

    忽略您已经通过
    ConcurrentHashMap
    访问了
    TreeMap
    这一事实-您最终会遇到多个线程同时访问
    TreeMap
    ,包括一个或多个线程写入映射。这是不安全的,因为对于这种情况,
    TreeMap
    不是线程安全的:

    请注意,此实现是不同步的。如果多个线程同时访问一个映射,并且至少有一个线程在结构上修改了映射,那么它必须在外部同步


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

    忽略您已经通过
    ConcurrentHashMap
    访问了
    TreeMap
    这一事实-您最终会遇到多个线程同时访问
    TreeMap
    ,包括一个或多个线程写入映射。这是不安全的,因为对于这种情况,
    TreeMap
    不是线程安全的:

    请注意,此实现是不同步的。如果多个线程同时访问一个映射,并且至少有一个线程在结构上修改了映射,那么它必须在外部同步


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


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

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


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

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

    1。是的,这是线程安全的,尽管在您将新创建的树映射放到CHM之前,其他线程无法看到它。但是这应该小心地实现以避免竞争条件-您应该确保检查和插入是以原子方式执行的:

    // 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);
    
    //在之前的某个位置创建一个空树映射
    TreeMap emptyMap=新的TreeMap();
    ...
    //在访问时,使用putIfAbsent方法确保
    //尝试同时获取没有关联值的相同密钥,
    //返回相同的空映射
    if(outerConcurrentMap.putIfAbsent(key,emptyMap)==null){
    emptyMap=新树映射();
    };
    map=outerConcurrentMap.get(键);
    
    2,3,4。否,首先需要通过显式锁定或使用
    synchronized
    锁定此树映射<代码>树映射本身不同步

    5。是的,这是在CHM上执行的操作,因此它是线程安全的


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

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

    1。是的,这是线程安全的,尽管在您将新创建的树映射放到CHM之前,其他线程无法看到它。但是这应该小心地实现以避免竞争条件-您应该确保检查和插入是以原子方式执行的:

    // 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);
    
    //在之前的某个位置创建一个空树映射
    TreeMap emptyMap=新的TreeMap();
    ...
    //在访问时,使用putIfAbsent方法确保
    //尝试同时获取没有关联值的相同密钥,
    //返回相同的空映射
    if(outerConcurrentMap.putIfAbsent(key,emptyMap)==null){
    emptyMap=新树映射();
    };
    map=outerConcurrentMap.get(键);
    
    2,3,4。否,首先需要通过显式锁定或使用
    synchronized
    锁定此树映射<代码>树形图