当两个锁定的线程(通过一个变量)切换它们的一个变量并尝试访问另一个时会发生什么?
What happens when two locked threads (by a variable), switch one of their variable and try to access another?
(我刚开始线程,所以我错的可能性很大)
如果相同class的两个线程,它们的一个变量进入同步方法,并且它们切换它们的一个变量,并尝试使用切换的变量访问另一个同步方法。会出现死锁吗?为什么?
我所说的一个例子: 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; }
}
}
主要是:
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()
}
如您所见,两个线程(一个和两个)被锁定在 synchronized (leftHand)
中,之后其中一个线程至少切换手(右手),然后 - 我们尝试访问synchronized (rightHand)
,可能发生了死锁。
我能理解逻辑,但是当我换手时,直觉上我认为我会复制另一只手的内容,但是我不明白为什么会出现死锁。
P.S我觉得我的标题不够准确,欢迎修改。
不要将您的代码视为在 leftHand
或 rightHand
上同步,因为那不是它正在做的事情。您实际上是在 whiteHand
或 blackHand
上同步。您的两个不同的 Person
对象,当 运行、 可能 看起来像这样:
Person one: synchronized whiteHand
Person two: synchronized blackHand
Person two: synchronized whiteHand
Person one: synchronized blackHand
你能看出这怎么行不通吗?您没有阻止其他线程在内部同步块上进行同步。第二个人有可能获得 blackHand
锁,然后等待第一个人释放 whiteHand
锁。但是,第一个人不会释放已经持有的 whiteHand
锁,因为它正在等待第二个人释放 blackHand
锁,而后者又在等待第一个人,依此类推。这种循环依赖会导致死锁。
此处的快速修复是简单地为每个 Person
实例使用一个锁,并通过将 color
设置为 final
使 Hand
线程安全。
之后,您需要将 name
设置为最终并同步对 friend
的访问,以使 Person
线程安全。
(我刚开始线程,所以我错的可能性很大)
如果相同class的两个线程,它们的一个变量进入同步方法,并且它们切换它们的一个变量,并尝试使用切换的变量访问另一个同步方法。会出现死锁吗?为什么?
我所说的一个例子: 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; }
}
}
主要是:
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()
}
如您所见,两个线程(一个和两个)被锁定在 synchronized (leftHand)
中,之后其中一个线程至少切换手(右手),然后 - 我们尝试访问synchronized (rightHand)
,可能发生了死锁。
我能理解逻辑,但是当我换手时,直觉上我认为我会复制另一只手的内容,但是我不明白为什么会出现死锁。
P.S我觉得我的标题不够准确,欢迎修改。
不要将您的代码视为在 leftHand
或 rightHand
上同步,因为那不是它正在做的事情。您实际上是在 whiteHand
或 blackHand
上同步。您的两个不同的 Person
对象,当 运行、 可能 看起来像这样:
Person one: synchronized whiteHand
Person two: synchronized blackHand
Person two: synchronized whiteHand
Person one: synchronized blackHand
你能看出这怎么行不通吗?您没有阻止其他线程在内部同步块上进行同步。第二个人有可能获得 blackHand
锁,然后等待第一个人释放 whiteHand
锁。但是,第一个人不会释放已经持有的 whiteHand
锁,因为它正在等待第二个人释放 blackHand
锁,而后者又在等待第一个人,依此类推。这种循环依赖会导致死锁。
此处的快速修复是简单地为每个 Person
实例使用一个锁,并通过将 color
设置为 final
使 Hand
线程安全。
之后,您需要将 name
设置为最终并同步对 friend
的访问,以使 Person
线程安全。