Is there a dead end in this method? How can I prevent this?

public void function(object a, object b){ synchronized(a){ synchronized (b){ a.performAction(b); b.performAction(a); } } } 

Dead end with two threads? Thanks for answers!

+6
source share
2 answers

Sure,

Suppose we have two objects:

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

And let thread 1 call:

 function(one, two); 

While thread 2 calls:

 function(two, one); 

On stream 1, a == one and b == two , but on stream 2, a == two and b == one .

Thus, although thread 1 receives a lock on object one, thread 2 can obtain a lock on object two. Then, when each thread tries to take the next step, they will be blocked.

+11
source

To avoid the problem posed in response to jame, you need to create a single lock to store both objects, regardless of the order they pass to the function:

 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(); } } 

And in your function, you need to somehow save the lock:

 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); } } 

Not optimal, but may work.

+2
source

Source: https://habr.com/ru/post/987878/


All Articles