代码之家  ›  专栏  ›  技术社区  ›  Tiina

java并发同步映射值

  •  10
  • Tiina  · 技术社区  · 6 年前

    下面的代码,我很困惑当两个线程竞争锁时会发生什么 map.get(k) . 当线程A获胜时 地图获取(k) 空,第二个线程将获得 synchronized(null) 是吗?或者是两个线程都认为 synchronized(v) 即使第一个线程将其更改为空,但在此期间,线程B仍将其视为 v ?

    synchronized(map.get(k)) {
       map.get(k).notify();
       map.remove(k);
    }
    

    这个问题与 another question ,但lock对象是映射的值。

    更新 以下内容: 比较了这篇文章和上面链接中的讨论,是不是真的

    synchronized(v) {
        v.notify();
        v = null;
    } 
    

    会导致第二个线程 已同步(空) 是的。但是为了 synchronized(map.get(k)) ,第二个线程将 同步(V) ????

    更新 以下内容: 要回答@holger的问题,这篇文章和另一篇文章的主要区别在于:

    final V v = new V();
    synchonized(map.get(k)) {
        map.get(k).notify();
        map.remove(k);
    }
    
    2 回复  |  直到 6 年前
        1
  •  9
  •   ernest_k Petronella    6 年前

    第二个线程不会“请求”锁定 thread.get(k) ,两个线程都将请求锁定 map.get(k) 之前 第一个开始执行。所以代码大致类似于:

    Object val = map.get(k);
    val.notify();
    

    因此,当获取锁的线程完成执行时,第二个线程仍将引用 Object val ,即使 map[k] 不再指向它(或指向 null )


    编辑 :(以下是许多有用的评论)

    好像锁上了 地图获取(k) 正在获取以确保只执行一次处理( map.remove(k) 在处理后调用)但确实有两个线程竞争锁 val 不会碰到的 null.notify() ,此代码的安全性无法保证 正如第二个线程可能调用的 synchronized(map.get(k)) 在第一个退出同步块之后 .

    以确保 k 如果是原子处理,可能需要更安全的方法。 一个 方法是使用并发哈希映射,如下所示:

    map.computeIfPresent(k, (key, value) -> {
        //process the value here
        //key is k
        //value is the value to which k is mapped.
    
        return null; //return null to remove the value after processing.
    });
    

    请注意 map 在前面的例子中是 ConcurrentHashMap 是的。这将确保值被处理一次( computeIfPresent 原子运行)。

    引用 ConcurrentHashMap.computeIfAbsent 文档注释:

    如果指定键的值存在,则尝试计算给定键及其当前映射值的新映射。整个方法调用是原子式执行的。在计算过程中,其他线程对此映射尝试的某些更新操作可能会被阻止,因此计算应该简短,并且不能尝试更新此映射的任何其他映射。

        2
  •  3
  •   Stephen C    6 年前

    会发生的是你会锁定这个值 目前 在键的hashmap项中 k .

    问题1-如果 map.get(k) 呼叫返回 null ,然后你会得到一个NPE。

    问题2-因为你没有锁定 map :

    • 您可能会得到与其他线程的争用条件;例如,如果其他线程执行 map.put(k, v) 与另一个不同 v 给你锁上的那个,还有
    • 这个 map.remove(k) 可能导致内存异常导致(潜在的)地图数据结构损坏。

    目前尚不清楚您通过同步 地图获取(k) (而不是 地图 )中。但不管是什么,这段代码都不是线程安全的。


    你的最新消息:是的,这是真的…假设其他线程正在对同一变量的值进行同步 . 注意你 总是 在对象上同步,因此 synchronized(v) ,这意味着“取 在那个物体上同步”。