2010-07-20 53 views
21

我们遇到了一个奇怪的问题ConcurrentHashMap,其中两个线程似乎呼吁put(),然后在方法Unsafe.park()内永远等待。从外部看,它看起来像ConcurrentHashMap内部的一个死锁。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] 
+6

你有线程转储吗? – 2010-07-20 17:26:55

+0

@John W .:好点。我会尽快将其从服务器上下载。 – 2010-07-20 18:52:42

+0

线程转储的任何其他部分是否显示哪个线程实际拥有该锁?这些线程正在等待获取。找出他们在等待什么可以提供帮助。 – 2010-07-22 15:22:47

回答

4

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

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

+0

此相关的错误看起来也非常接近:http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6822370。我们会尝试升级到最新的Java 6版本,因为后面的错误已被修复。感谢您发布此信息。 – 2010-07-21 07:20:03

4

包装不安全是本地人,实现依赖于一个平台上。

突然终止第三个线程(在平台级别上,excepion不是问题),它在地图上获取锁定可能导致此类情况 - 锁定状态中断,另外两个线程被禁用并等待某人调用Unsafe。 unpark()(那永远不会发生)。

5

我不认为这是你的情况发生了什么,但是可以用一个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之间有一百个事件回调堆栈帧,那么跟踪起来可能非常困难。

相关问题