|
[java]
Use Total Ordering of Objects to Avoid Deadlocks
[
jonas
]
Writing multi-threaded applications in Java can as you know be quite tricky, and if not done correctly, one can easily end up with deadlock situations. For example, take a look at this little code snippet. This piece of Java code implements a Node, which has three methods (that is of our interest):
Here's the implementation: public class Node { private Object value; public synchronized Object get() { return value; } public synchronized void set(Object value) { this.value = value; } public synchronized void swap(Node n) { Object tmp = get(); set(n.get()); n.set(tmp); } ... // remaining methods omitted }
This class might look okay, but it actually suffers from potential deadlock. For example what happens if, one thread T1 invokes
Thread T1 acquires the lock for node n1, and thread T2 acquires the lock for node n2. Thread T1 now invokes This program is however easily fixed by using the technique of totally ordering all objects in the system.
public class Node { private Object value; public synchronized Object get() { return value; } public synchronized void set(Object value) { this.value = value; } private synchronized void doSwap(Node n) { Object tmp = get(); set(n.get()); n.set(tmp); } public void swap(Node n) { if (this == n) { return; } else if (System.identityHashCode(this) < System.identityHashCode(n)) { doSwap(n); } else { n.doSwap(this); } } ... // remaining methods omitted } In this program, all locks will be acquired in increasing order, guaranteed to be the same for all threads, and thereby avoiding deadlock situations. TrackBackUnfortunately, you can have two distinct objects --Tom Tromey, July 27, 2005 10:40 AM
I would make void Node#doSwap(Node) either private or name it something like doInsecureSwap(Node) --Marko Schulz, July 27, 2005 11:17 AM
Right, changed it to private... --Jonas, July 27, 2005 11:53 AM
Clever. To address Tom's point, you could keep an internal static counter instead of using the identity hash code. The exact details depend on the lifecycle of Node. I would probably decouple the client from the nodes using a container class. --Bob Lee, July 27, 2005 04:17 PM
I don't see, where there could be a deadlock. If you call n1.swap(n2), it invokes n1.get() and n2.swap(n1) invokes n2.get(). Both getters are locked. And your solution calls in both cases n1.doSwap(n2). In this case, it results the same way as n1.swap(n2) and n2.swap(n1) in the first listing do. --Newlukai, July 28, 2005 09:18 AM
A synchronized member method is locking the instance (e.g. synchronized(this)), not the method itself. --Jonas, July 28, 2005 03:45 PM
Post a comment
|