【问题标题】:What happens when two locked threads (by a variable), switch one of their variable and try to access another?当两个锁定的线程(通过一个变量)切换它们的一个变量并尝试访问另一个时会发生什么?
【发布时间】:2017-12-29 18:58:36
【问题描述】:

(我刚刚开始发帖,所以很有可能我会错)

如果同一类的两个线程,其中一个变量进入同步方法,它们切换其中一个变量,并尝试使用切换变量访问另一个同步方法。会发生死锁吗?为什么?

我正在谈论的一个例子:类:

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 我觉得我的标题不够准确,所以欢迎编辑。

【问题讨论】:

  • 此代码目前甚至无法编译。请修复它,以便清楚您在说什么。
  • 已修复。如果你运行它几次,它最终会进入一个块。真正的类有函数在路上,所以总是发生死锁
  • Re,“同一类的两个线程。”线程不属于任何类。线程是执行代码的东西。线程开始执行的run() 方法必须属于某个类,因为在Java 中,每个 方法都必须属于某个类;但这并没有在线程和类之间建立任何特殊关系。线程就是执行你给它的任何对象的run() 方法的东西。
  • Re,“其中一个变量进入了同步方法。”这没有任何意义。变量不会“进入”(或退出)方法或任何其他地方。静态变量保留在声明它们的类中,实例变量保留在创建它们的对象中,而局部变量保留在创建它们的函数激活中。变量不是可以移动的东西。但有时我们会谈论将从一个变量移动到另一个变量。
  • 另外,线程可以进入(即“调用”)或退出(即“返回”)方法。

标签: java multithreading synchronization deadlock synchronized


【解决方案1】:

不要认为您的代码在 leftHandrightHand 上同步,因为这不是它正在做的事情。您确实在 whiteHandblackHand 上同步。您的两个不同的 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 设置为final 并同步对friend 的访问,以使Person 线程安全。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2013-07-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-11-15
    • 1970-01-01
    相关资源
    最近更新 更多