我们遇到了ConcurrentHashMap
的一个奇怪问题,其中两个线程似乎在调用put()
,然后在方法Unsafe.park()
内永远等待。从外面看,它看起来像ConcurrentHashMap
内的僵局。
到目前为止,我们只看到过这种情况。
有人能想到任何可能导致这些症状的事吗?
编辑:相关主题的主题转储在此处:
"[redacted] Thread 2" prio=10 tid=0x000000005bbbc800 nid=0x921 waiting on condition [0x0000000040e93000] java.lang.Thread.State: WAITING (parking) at sun.misc.Unsafe.park(Native Method) - parking to wait for <0x00002aaaf1207b40> (a 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) at [redacted] "[redacted] Thread 0" prio=10 tid=0x000000005bf38000 nid=0x91f waiting on condition [0x000000004151d000] java.lang.Thread.State: WAITING (parking) at sun.misc.Unsafe.park(Native Method) - parking to wait for <0x00002aaaf1207b40> (a 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) at [redacted]
答案 0 :(得分:7)
我不认为这是你的情况下发生的事情,但是可以用ConcurrentHashMap
的单个实例编写死锁,它只需要一个线程!让我坚持了一段时间。
我们假设您正在使用ConcurrentHashMap<String, Integer>
来计算直方图。你可能会这样做:
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<K,V> (id=25)
ConcurrentHashMap<K,V>.putVal(K, V, boolean) line: not available
ConcurrentHashMap<K,V>.putIfAbsent(K, V) line: not available
ConcurrentHashMapDeadlock.lambda$0(ConcurrentHashMap, String, Integer) line: 32
1613255205.apply(Object, Object) line: not available
ConcurrentHashMap<K,V>.compute(K, BiFunction<? super K,? super V,? extends V>) line: not available
在上面的示例中,我们很容易看到我们正在尝试修改原子修改中的地图,这似乎是一个坏主意。但是,如果在调用map.compute
和map.putIfAbsent
之间有一百个事件回调堆栈帧,那么跟踪就很难了。
答案 1 :(得分:4)
也许不是你想要的答案,但这可能是一个JVM错误。参见
答案 2 :(得分:4)
Package Unsafe是原生的,实现取决于平台。
在地图上获得锁定的第三个线程突然终止(在平台级别,例外不是问题)可能导致这种情况 - 锁定状态被破坏,另外两个线程被禁用并等待某人调用Unsafe.unpark ()(这永远不会发生)。