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.
fonte
2015-05-25 21:00:47
No, entrambi i thread attenderanno 'a'. Potrebbe essere se esistesse un secondo metodo in cui prima sincronizzi su "b" e poi su "a". – Stan
Quindi se performAction() usasse l'oggetto a in un metodo sincronizzato ci sarebbe un deadlock per esempio? – MrBoolean
Nel caso in cui no dal thread 1 attenderà il rilascio dell'oggetto 'a' fino alla fine del metodo – Stan