(I just started threads, so there is a big chance I'll be wrong)
If two threads of the same class, one of their variables gets into a synchronized method, and they switch one of their variables, and try to access another synchronized method using a switched variable. a deadlock will occur? and why?
An example of what I'm talking about: The class:
public class Person extends Thread{
public Hand leftHand;
public Hand rightHand;
public String name;
public Person friend;
public Person(Hand a, Hand b, String name, Person f){
this.leftHand = a;
this.rightHand = b;
this.name = name;
this.friend = f;
}
public void switchHands(){
if(leftHand.color.equals(rightHand.color)){
Hand temp = this.rightHand;
this.rightHand = friend.rightHand;
friend.rightHand = temp;
}
}
public void run(){
synchronized (leftHand){
System.out.println(this.name + " locked with " + this.leftHand);
switchHands();
synchronized (rightHand){
System.out.println(this.name + " locked with " + this.rightHand);
}
}
}
public static class Hand{
String color;
public Hand(String c){ this.color = c; }
}
}
And in the main:
public static void main(String[] args){
Hand whiteHand = new Hand("white");
Hand blackHand = new Hand("black");
Person one = new Person(whiteHand, whiteHand, "one", null);
Person second = new Person(blackHand, blackHand, "second", null);
one.friend = second;
second.friend = one;
one.start();
second.start()
}
as you can see, the two threads (one and two), gets locked in synchronized (leftHand)
, afterwards one of the threads at least switch hands (the right hand), and then - we try to access synchronized (rightHand)
, and a deadlock probably occurred.
I can understand the logic, but when I switch the hands, intuitively I think I'll just copy the content of the other hand, but I don't understand why a deadlock occurs.
P.S I think my title is not precise enough, so an edit will be welcome.
Don't think about your code as synchronizing on leftHand
or rightHand
because that's not what it is doing. You're really synchronizing on either whiteHand
or blackHand
. Your two different Person
objects, when run, could look something like this:
Person one: synchronized whiteHand
Person two: synchronized blackHand
Person two: synchronized whiteHand
Person one: synchronized blackHand
Can you see how this will not work? You have not prevented the other thread from synchronizing on the inner synchronized block. It is possible for Person two to acquire the blackHand
lock, and then wait for Person one to release the whiteHand
lock. However, Person one won't release the already held whiteHand
lock, because it is waiting for Person two to release the blackHand
lock, which in turn is waiting for Person one and so on and so forth. This cyclic dependency will lead to deadlock.
The quick fix here is to simply use a lock per instance of Person
and make Hand
thread safe by setting the color
to final
.
After that, you'd need to set name
to final and synchronize access to friend
in order to make Person
thread safe.