在这种情况下是否有可能通过ConcurrentHashMap获得死锁?

问题描述 投票:13回答:1

我正在读取JDK8中的ConcurrentHashMap的源代码,请注意TreeBin使用“读写”锁来防止并发读写。

如果没有并发写入线程试图修改树结构,则读取线程将通过TreeNodes。当“查找”操作完成时,读取线程可能会:

(1)'CAS'lockState,如果存在该线程,则“释放”该waiter(writer)线程。

以下是源代码中的'find()'方法。

final Node<K,V> find(int h, Object k) {
            if (k != null) {
                for (Node<K,V> e = first; e != null; ) {
                    int s; K ek;
                    if (((s = lockState) & (WAITER|WRITER)) != 0) {
                        if (e.hash == h &&
                            ((ek = e.key) == k || (ek != null && k.equals(ek))))
                            return e;
                        e = e.next;
                    }
                    else if (U.compareAndSwapInt(this, LOCKSTATE, s,
                                                 s + READER)) {
                        TreeNode<K,V> r, p;
                        try {
                            p = ((r = root) == null ? null :
                                 r.findTreeNode(h, k, null));
                        } finally {
                            Thread w;
                            // (1)if no more readers, try to unpark the waiter if it exists
                            if (U.getAndAddInt(this, LOCKSTATE, -READER) ==
                                (READER|WAITER) && (w = waiter) != null)
                                LockSupport.unpark(w);
                        }
                        return p;
                    }
                }
            }
            return null;
        }

另一方面,编写者线程可以:

  • ((2)通过'CAS'操作将WAITER状态添加到lockState

  • ((3)设置为waiter变量。

  • ((4)'park'本身。

这是作者的代码:

        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);
            }
        }

这是我的困惑:

如果上面的四个操作按(2)(1)(3)(4)的顺序运行,则操作(1)不会取消任何操作,因为此时“ waiter”为空。

然后服务员将永远停放而没有任何人可以将其停放。

[随后的写操作将全部被'parked'线程持有的固有锁阻塞。

这是否有死锁机会?

我对此感到非常困惑。我想也许我已经错过了源代码中的某些内容。如果您熟悉的话,需要您的帮助。

java deadlock java.util.concurrent concurrenthashmap
1个回答
0
投票
© www.soinside.com 2019 - 2024. All rights reserved.