2010-07-20 143 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之間有一百個事件回調堆棧幀,那麼跟蹤起來可能非常困難。