【问题标题】:Is it possible to get a deadlock with ConcurrentHashMap with two threads lockRoot是否有可能使用 ConcurrentHashMap 与两个线程 lockRoot 发生死锁
【发布时间】:2022-01-01 15:00:52
【问题描述】:

如果两个线程同时将 val 放入一棵树中

private final void contendedLock() {
        boolean waiting = false;
        for (int s;;) {
            if (((s = lockState) & ~WAITER) == 0) {
                if (U.compareAndSwapInt(this, LOCKSTATE, s, WRITER)) {
                    if (waiting)
                        waiter = null;
                    return;
                }
            }
            else if ((s & WAITER) == 0) {
                if (U.compareAndSwapInt(this, LOCKSTATE, s, s | WAITER)) {
                    waiting = true;
                    waiter = Thread.currentThread();
                }
            }
            else if (waiting)
                LockSupport.park(this);
        }
    }

Thread1:CAS 将锁状态写入 WRITER

Thread2:CAS 锁定状态到 (WRITER|WAITER)

Thread2:LockSupport.park(this)

Thread1:unlockRoot

private final void unlockRoot() {
        lockState = 0;
    }

那么谁能解除 Thread2 的停放?

find()方法的finally部分需要在严格的条件下完成

finally {
                        Thread w;
                        if (U.getAndAddInt(this, LOCKSTATE, -READER) ==
                            (READER|WAITER) && (w = waiter) != null)
                            LockSupport.unpark(w);
                    }

如果我想错了,谁能告诉我?

【问题讨论】:

    标签: java java.util.concurrent concurrenthashmap


    【解决方案1】:

    您的推理基于这样的假设,即 2 个写入器线程可能会进入 contendedLock() 方法,而第二个写入器将无限期地自行停放,这当然是不可能的,因为 putVal 是相关树的synchronized on the root node

    事实上,lockState 仅用于通过 CAS 编排读取器与写入器,并且仅当读取器和写入器都尝试访问相同的 RB-tree 时(即它们都在具有相同哈希的键上操作)。

    在这种情况下,一旦发现lockState=READER,写入器线程将自行停止(然后通过 OR(s | WAITER)将WAITER 位添加到lockState。此值(00000110)稍后将被使用在阅读器的finally块中取消写入器线程(一旦它通过添加-READER清除阅读状态,即-4,并且看到以前的值也是00000110)

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-05-08
      • 2019-02-23
      • 1970-01-01
      • 2013-12-13
      相关资源
      最近更新 更多