2015-05-25 13 views
6
public void function(object a, object b){ 
    synchronized(a){ 
     synchronized (b){ 
      a.performAction(b); 
      b.performAction(a); 
     } 
    } 
} 

Deadlock con 2 fili? Grazie per le risposte!È possibile un deadlock in questo metodo? Come posso impedirlo?

+0

No, entrambi i thread attenderanno 'a'. Potrebbe essere se esistesse un secondo metodo in cui prima sincronizzi su "b" e poi su "a". – Stan

+0

Quindi se performAction() usasse l'oggetto a in un metodo sincronizzato ci sarebbe un deadlock per esempio? – MrBoolean

+0

Nel caso in cui no dal thread 1 attenderà il rilascio dell'oggetto 'a' fino alla fine del metodo – Stan

risposta

11

Certo,

Supponiamo di avere due oggetti,

Object one = ...; 
Object two = ...; 

e supponiamo filo 1 chiamate:

function(one, two); 

mentre il thread 2 chiamate:

function(two, one); 

In discussione 1, a == one e b == two, ma nella filettatura 2, a == two e b == one.

Così mentre il thread 1 sta ottenendo un blocco sull'oggetto uno, il thread 2 può ottenere il blocco sull'oggetto due. Quindi, quando ognuno dei thread tenta di fare il passo successivo, saranno bloccati.

+0

È possibile risolvere il problema bloccando l'ordine hashcode asc/desc. Comunque non è carino. – Aitch

2

per evitare il problema dichiarato dalla risposta di jame, è necessario creare un singolo blocco di tenere entrambi gli oggetti, non importa l'ordine in cui vengono passati alla funzione:

public class TwoObjectsLock { 
    private Object a; 
    private Object b; 

    public TwoObjectsLock(Object a, Object b){ 
     this.a = a; 
     this.b = b; 
    } 

    @Override 
    public void equals(Object obj){ 
     if (this == obj) return true; 
     if (obj instanceof TwoObjectsLock){ 
      TwoObjectsLock that = (TwoObjectsLock) obj; 
      return (this.a.equals(that.a) && this.b.equals(that.b)) || 
        (this.a.equals(that.b) && this.b.equals(that.a)); 
     } 
     return false; 
    } 

    @Override 
    public int hashCode(){ 
     return a.hashCode() + b.hashCode(); 
    } 
} 

E nella vostra funzione è necessario memorizzare il blocco in qualche modo:

private final Map<TwoObjectsLock, TwoObjectsLock> lockInstances = new HashMap<>(); 

public void function(Object a, Object b){ 
    TwoObjectsLock lock = new TwoObjectsLock(a,b); 
    synchronized(lockInstances){ 
     TwoObjectsLock otherLock = lockInstances.get(lock); 
     if (otherLock == null){ 
      lockInstances.put(lock, lock); 
     } 
     else { 
      lock = otherLock; 
     } 
    } 

    synchronized(lock){ 
     a.performAction(b); 
     b.performAction(a); 
    } 
} 

Non ottimale ma può funzionare.

Problemi correlati