简体   繁体   English

为什么这个程序中的同一个对象没有死锁 - Java 多线程

[英]Why no deadlock on the same object in this program - Java Multithreading

I have three classes below.我有以下三节课。 Main, two threads and Obj whose methods are synchronized Main,两个线程和方法同步的Obj

public class DeadLocks {

    public static void main(String[] args) {
        SyncObj so = new SyncObj();
        ThreadObj to = new ThreadObj(so);
        ThreadObj1 to1 = new ThreadObj1(so);

        to.start();
        to1.start();
    }
}

class SyncObj {
    synchronized void foo() {
        System.out.println("Foo Started");
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        bar();
    }

    synchronized void bar() {
        System.out.println("bar started");
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        foo();
    }

}

class ThreadObj1 extends Thread {
    SyncObj so;

    public ThreadObj1(SyncObj so) {
        this.so = so;
    }

    @Override
    public void run() {
        so.bar();
    }
}

class ThreadObj extends Thread {
    SyncObj so;

    public ThreadObj(SyncObj so) {
        this.so = so;
    }

    @Override
    public void run() {
        so.foo();
    }
}

In the above code I'm calling synchronized methods on the same object.在上面的代码中,我在同一个对象上调用了同步方法。 Both the methods are executing and calling each other simultaneously.There is no deadlock situation.两个方法同时执行和调用,不存在死锁情况。 Could anyone explain why?谁能解释一下为什么? sorry for such a silly question.抱歉问了这么愚蠢的问题。

As far as I can see, you are using the same object ( so ) for both the cases.据我所知,您在这两种情况下都使用相同的对象( so )。 So there is no case for a deadlock.所以没有死锁的情况。 You would need to lock on two or more objects wherein each critical section requires the lock other than the one that it is holding.您需要锁定两个或多个对象,其中每个临界区都需要与它持有的锁不同的锁。 That other lock is held by "another" thread.另一个锁由“另一个”线程持有。

Confusing, this will enlighten: " https://docs.oracle.com/javase/tutorial/essential/concurrency/deadlock.html "令人困惑,这将启发:“ https://docs.oracle.com/javase/tutorial/essential/concurrency/deadlock.html

You would never ever deadlock in a scenario that you describe.在您描述的场景中,您never ever deadlock In this scenario there is only one so that is being shared and is being synchronized with.在这种情况下,只有一个so正被共享,并且正在与同步。

Let me give you an example to illustrate:我举个例子来说明一下:

Suppose Andy and Sandy are playing with two soccer balls B1 and B2 .假设安迪和桑迪正在玩两个足球B1B2

Now further suppose that both Andy and Sandy have balls B1 and B2 in their possession respectively.现在进一步假设 Andy 和 Sandy 分别拥有球B1B2 For example Andy has ball B1 and Sandy has ball B2 .例如,安迪有球B1 ,桑迪有球B2

Now they devise a game wherein they need both the balls each.现在他们设计了一个游戏,其中每个人都需要两个球。 Now Sandy wants ball B1 as well and at the same time, Andy wants B2 .现在 Sandy 也想要B1球,同时,Andy 想要B2 球

And both of them cannot relinquish the balls that they hold.并且他们两个都不能放弃他们持有的球。 Andy will not give up B1 and vice-versa.安迪不会放弃B1 ,反之亦然。

So both of them cannot continue and are stuck. We call this a deadlocked situation.

Hope this example helps.希望这个例子有帮助。 You could use your imagination to increase the number of balls in play to 3 or 4 (and so on..) and / or increase the number of players.您可以发挥您的想象力将比赛中的球数增加到 3 或 4 个(依此类推……)和/或增加球员人数。

You do not get a deadlock because your program does not meet two of the four necessary conditions of forming it:您不会遇到死锁,因为您的程序不满足形成它的四个必要条件中的两个:

  • mutual exclusion - yes,互斥- 是的,
  • hold on partial allocation - no,保持部分分配- 不,
  • no pre-emption - yes,没有先发制人- 是的,
  • circular dependency - no循环依赖- 没有

You need at least two resources, "A" and "B", to form a deadlock.您至少需要两个资源“A”和“B”才能形成死锁。 One thread should grab "A" and attempt to grab "B", while the other should grab "B", and attempt to grab "A".一个线程应该抓取“A”并尝试抓取“B”,而另一个线程应该抓取“B”并尝试抓取“A”。

I'm not sure why you expect a deadlock here.我不知道你为什么期望这里会出现僵局。 It's true that only one of objects has an access to synchronized section, but then it has this access as much as it wants.确实只有一个对象可以访问同步部分,但是它可以随心所欲地访问。 You can modify the code to make it clear:您可以修改代码以使其清楚:

public class DeadLocks {

     public static void main(String[] args) {
         SyncObj so = new SyncObj();
         ThreadObj to = new ThreadObj(so);
         ThreadObj1 to1 = new ThreadObj1(so);

         to.start();
         to1.start();
     }
 }

 class SyncObj {
     synchronized void foo(String msg) {
         System.out.println("Foo Started: " + msg);
         try {
             Thread.sleep(1000);
         } catch (InterruptedException e) {
             e.printStackTrace();
         }
         bar(msg);
     }

     synchronized void bar(String msg) {
         System.out.println("bar started: " + msg);
         try {
             Thread.sleep(1000);
         } catch (InterruptedException e) {
             e.printStackTrace();
         }
         foo(msg);
     }

 }

 class ThreadObj1 extends Thread {
     SyncObj so;

     public ThreadObj1(SyncObj so) {
         this.so = so;
     }

     @Override
     public void run() {
         so.bar("TO1");
     }
 }

 class ThreadObj extends Thread {
     SyncObj so;

     public ThreadObj(SyncObj so) {
         this.so = so;
     }

     @Override
     public void run() {
         so.foo("TO");
     }
 }

You can see the following output:您可以看到以下输出:

Foo Started: TO
bar started: TO
Foo Started: TO
bar started: TO
Foo Started: TO
bar started: TO

You can consider 'synchronized' to mean lock(this), where 'this' is a SyncObj instance.您可以将 'synchronized' 视为 lock(this),其中 'this' 是一个 SyncObj 实例。 Therefore there is exactly one lock, and it's impossible to obtain a deadlock.因此只有一个锁,不可能获得死锁。

While others have already pointed out that a deadlock only occurs when you have two resources where each thread locks one and then waits for the other, I think there is one crucial point missing, where your entire confusion probably comes from:虽然其他人已经指出只有当你有两个资源时才会发生死锁,其中每个线程锁定一个然后等待另一个,但我认为缺少一个关键点,你的整个困惑可能来自:

synchronize on a method does not create a lock for that particular method, it creates a lock for the entire object it belongs to.方法上的synchronize不会为该特定方法创建锁,而是为其所属的整个对象创建锁。 Thus your class is equivalent to this:因此,您的课程相当于:

class SyncObj {
    void foo() {
        synchronized(this) {
            System.out.println("Foo Started");
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            bar();
        }
    }

    void bar() {
        synchronized(this) {
          System.out.println("bar started");
          try {
              Thread.sleep(1000);
          } catch (InterruptedException e) {
              e.printStackTrace();
          }
          foo();
        }
    }
}

Now it should be much more clear, why you don't get a deadlock.现在应该更清楚了,为什么你没有陷入僵局。

You can easily modify your code to be prone to a deadlock by introducing two resources, one for each method:您可以通过引入两种资源(每个方法一个)来轻松修改代码,使其容易出现死锁:

class SyncObj {
    private Object foolock = new Object();
    private Object barlock = new Object();

    void foo() {
        synchronized(foolock) {
            System.out.println("Foo Started");
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            bar();
        }
    }

    void bar() {
        synchronized(barlock) {
          System.out.println("bar started");
          try {
              Thread.sleep(1000);
          } catch (InterruptedException e) {
              e.printStackTrace();
          }
          foo();
        }
    }
}

Deadlock is not possible using a single instance because no two threads of the same object can access more than one synchronised method.使用单个实例不可能发生死锁,因为同一个对象的两个线程不能访问多个同步方法。 In the above example if thread 1 is accessing foo method.在上面的例子中,如果线程 1 正在访问 foo 方法。 Thread 2 cannot access either foo nor bar method.线程 2 不能访问 foo 或 bar 方法。 Untill thread 1 finishes it task直到线程 1 完成它的任务

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM