ConcurrentHashMap是否有可能“死锁”?

2022-09-01 21:18:50

我们遇到了一个奇怪的问题,其中两个线程似乎正在调用 ,然后在方法中永远等待。从外面看,它看起来像一个死锁里面 。ConcurrentHashMapput()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]

答案 1

我不认为这是在你的情况下发生的事情,但是可以用一个实例写一个死锁,它只需要一个线程!让我卡了很长一段时间。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.computemap.putIfAbsent


答案 2

也许不是你想要的答案,但这可能是一个JVM错误。参见 JDK 6865591

Test6471091.java在 Solaris-i586 上挂起


推荐