ConcurrentHashMap是否可能“死锁”?

我们遇到了ConcurrentHashMap一个奇怪问题,其中两个线程似乎在调用put() ,然后在方法Unsafe.park()内永远等待。 从外部看,它看起来像ConcurrentHashMap的死锁。

到目前为止,我们只看到过这种情况。

谁能想到任何可能导致这些症状的事情?

编辑 :相关线程的线程转储在这里:


 “[编辑]线程2”prio = 10 tid = 0x000000005bbbc800 nid = 0x921等待条件[0x0000000040e93000]
    java.lang.Thread.State:WAITING(停车)
    在sun.misc.Unsafe.park(原生方法)
     - 停车等待(java.util.concurrent.locks.ReentrantLock $ NonfairSync)
     at java.util.concurrent.locks.LockSupport.park(LockSupport.java:158)
     at java.util.concurrent.locks.AbstractQueuedSynchronizer.parkAndCheckInterrupt(AbstractQueuedSynchronizer.java:747)
     at java.util.concurrent.locks.AbstractQueuedSynchronizer.acquireQueued(AbstractQueuedSynchronizer.java:778)
     at java.util.concurrent.locks.AbstractQueuedSynchronizer.acquire(AbstractQueuedSynchronizer.java:1114)
     at java.util.concurrent.locks.ReentrantLock $ NonfairSync.lock(ReentrantLock.java:186)
     at java.util.concurrent.locks.ReentrantLock.lock(ReentrantLock.java:262)
     at java.util.concurrent.ConcurrentHashMap $ Segment.put(ConcurrentHashMap.java:417)
     at java.util.concurrent.ConcurrentHashMap.put(ConcurrentHashMap.java:883)
    在[编辑]


 “[编辑]线程0”prio = 10 tid = 0x000000005bf38000 nid = 0x91f等待条件[0x000000004151d000]
    java.lang.Thread.State:WAITING(停车)
    在sun.misc.Unsafe.park(原生方法)
     - 停车等待(java.util.concurrent.locks.ReentrantLock $ NonfairSync)
     at java.util.concurrent.locks.LockSupport.park(LockSupport.java:158)
     at java.util.concurrent.locks.AbstractQueuedSynchronizer.parkAndCheckInterrupt(AbstractQueuedSynchronizer.java:747)
     at java.util.concurrent.locks.AbstractQueuedSynchronizer.acquireQueued(AbstractQueuedSynchronizer.java:778)
     at java.util.concurrent.locks.AbstractQueuedSynchronizer.acquire(AbstractQueuedSynchronizer.java:1114)
     at java.util.concurrent.locks.ReentrantLock $ NonfairSync.lock(ReentrantLock.java:186)
     at java.util.concurrent.locks.ReentrantLock.lock(ReentrantLock.java:262)
     at java.util.concurrent.ConcurrentHashMap $ Segment.put(ConcurrentHashMap.java:417)
     at java.util.concurrent.ConcurrentHashMap.put(ConcurrentHashMap.java:883)
    在[编辑]

也许不是你想要的答案,但这可能是一个JVM错误。 看到

http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6865591

我不认为这是你的情况下发生的事情,但是可以用ConcurrentHashMap的单个实例写一个死锁,它只需要一个线程! 让我坚持了很长一段时间。

假设您正在使用ConcurrentHashMap来计算直方图。 你可能会这样做:

 int count = map.compute(key, (k, oldValue) -> { return oldValue == null ? 1 : oldValue + 1; }); 

哪个工作得很好。

但是,让我们说你决定改写它:

 int count = map.compute(key, (k, oldValue) -> { return map.putIfAbsent(k, 0) + 1; }); 

你现在将获得一个带有这样的堆栈的1线程死锁:

 Thread [main] (Suspended) owns: ConcurrentHashMap$ReservationNode (id=25) ConcurrentHashMap.putVal(K, V, boolean) line: not available ConcurrentHashMap.putIfAbsent(K, V) line: not available ConcurrentHashMapDeadlock.lambda$0(ConcurrentHashMap, String, Integer) line: 32 1613255205.apply(Object, Object) line: not available ConcurrentHashMap.compute(K, BiFunction) line: not available 

在上面的例子中,很容易看出我们正在尝试修改primefaces修改中的映射,这看起来是个坏主意。 但是,如果在调用map.computemap.putIfAbsent之间有一百个事件回调堆栈帧,则跟踪起来可能非常困难。

Package Unsafe是原生的,实现依赖于平台。

突然终止第三个线程(在平台级别,例外不是问题)在地图上获得锁定可能导致这种情况 – 锁定状态被破坏,另外两个线程被禁用并等待某人调用Unsafe.unpark()(这永远不会发生)。