Domanda

Abbiamo incontrato uno strano problema con ConcurrentHashMap, in cui due thread sembra chiamare put(), quindi in attesa per sempre all'interno del metodo Unsafe.park().Dall'esterno, sembra un deadlock all'interno ConcurrentHashMap.

Abbiamo visto solo questo accadere una volta finora.

Qualcuno può pensare a tutto ciò che potrebbe causare questi sintomi?

Modifica : La discarica del thread per i thread pertinenti è qui:

"[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]
.

È stato utile?

Soluzione

Forse non la risposta che vuoi, ma questo potrebbe essere un bug JVM.Vedi

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

Altri suggerimenti

Non penso che questo sia ciò che sta accadendo nel tuo caso, ma è possibile scrivere un deadlock con un'unica istanza di ConcurrentHashMap e necessita solo di un thread!Mi ha tenuto bloccato per un bel po '.

Diciamo che stai usando un ConcurrentHashMap<String, Integer> per calcolare un istogramma.Potresti fare qualcosa del genere:

int count = map.compute(key, (k, oldValue) -> {
    return oldValue == null ? 1 : oldValue + 1;
});
.

che funziona bene.

Ma diciamo che decidi invece di scriverlo come questo:

int count = map.compute(key, (k, oldValue) -> {
    return map.putIfAbsent(k, 0) + 1;
});
.

Otterrai ora un deadlock a 1 fili con uno stack come questo:

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  
.

Nell'esempio sopra, è facile vedere che stiamo tentando di modificare la mappa all'interno di una modifica atomica, che sembra una cattiva idea.Tuttavia, se ci sono un centinaio di fotogrammi di stack di callback-callback tra la chiamata a map.compute e map.putIfAbsent, quindi può essere abbastanza difficile da rintracciare.

Pacchetto non sicuro è nativo, un'attuazione dipende da una piattaforma.

Terminazione brusca del terzo thread (a livello di piattaforma, l'eccezione non è un problema) che ha acquisito un blocco sulla mappa può causare tale situazione: lo stato di blocco è rotto, altri due fili sono disabilitati e in attesa di qualcuno di chiamare non sicuro.unpark() (E questo non accadrà mai).

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top