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错误。 看到
我不认为这是你的情况下发生的事情,但是可以用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 super K,? super V,? extends V>) line: not available
在上面的例子中,很容易看出我们正在尝试修改primefaces修改中的映射,这看起来是个坏主意。 但是,如果在调用map.compute
和map.putIfAbsent
之间有一百个事件回调堆栈帧,则跟踪起来可能非常困难。
Package Unsafe是原生的,实现依赖于平台。
突然终止第三个线程(在平台级别,例外不是问题)在地图上获得锁定可能导致这种情况 – 锁定状态被破坏,另外两个线程被禁用并等待某人调用Unsafe.unpark()(这永远不会发生)。