当两个锁定线程(通过变量),切换其中一个变量并尝试访问另一个变量时会发生什么?

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了当两个锁定线程(通过变量),切换其中一个变量并尝试访问另一个变量时会发生什么?相关的知识,希望对你有一定的参考价值。

(我刚刚开始使用线程,所以我很有可能会出错)

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

我正在谈论的一个例子:课程:

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我认为我的标题不够精确,所以欢迎编辑。

答案

不要认为你的代码在leftHandrightHand上同步,因为那不是它正在做的事情。你真的在whiteHandblackHand同步。运行时,你的两个不同的Person对象看起来像这样:

Person one: synchronized whiteHand
Person two: synchronized blackHand
Person two: synchronized whiteHand
Person one: synchronized blackHand

你能看出这不起作用吗?您还没有阻止其他线程在内部同步块上进行同步。 Person 2有可能获得blackHand锁,然后等待Person 1释放whiteHand锁。但是,Person one不会释放已经持有的whiteHand锁,因为它正在等待Person 2释放blackHand锁,而后者又等待Person one等等等等。这种循环依赖将导致死锁。

这里的快速解决方法是简单地使用每个Person实例的锁定,并通过将Hand设置为color来使final线程安全。

之后,你需要将name设置为final并同步访问friend以使Person线程安全。

以上是关于当两个锁定线程(通过变量),切换其中一个变量并尝试访问另一个变量时会发生什么?的主要内容,如果未能解决你的问题,请参考以下文章

四十Linux 线程——线程同步之条件变量

c# 多线程互斥问题。。

并发编程:volatile关键字

从两个线程访问锁定映射和向量

qt多线程中怎样锁定一个指定的变量?

Qt入门教程QObject篇线程同步