【问题标题】:why doesn't deadlock occur in this situation为什么在这种情况下不会发生死锁
【发布时间】:2018-05-16 13:43:10
【问题描述】:
public class TestClass {

public synchronized void func1() throws InterruptedException {
        System.out.println("func1");
        long a = System.nanoTime();
        func2();

}

public synchronized void func2() throws InterruptedException {
        System.out.println("func2");
        long a = System.nanoTime();
        while (System.nanoTime() - a < 10000000) {
            ;
        }

        func1();

} }

public class ThreadSample extends Thread {

TestClass testClass;
public ThreadSample(TestClass testClass)
{
    this.testClass = testClass;
}
@Override
public void run() {
    try {
        testClass.func2();
    } catch (InterruptedException e) {
        e.printStackTrace();
    }

}}

public class Main {
public static void main(String[] args) throws InterruptedException {

    TestClass testClass = new TestClass();
    ThreadSample threadSample  = new ThreadSample(testClass);
    threadSample.start();
    testClass.func1();
}}

请看上面的代码。为什么这里不会发生死锁?因为主线程在 func1 中并且想去 func2 但它不能因为 func2 被 ThreadSample 锁定。和 ThreadSample 也不能去 func1。所以我们应该面临僵局,但我们没有。

为什么?

【问题讨论】:

  • (也许我对死锁的理解不正确) func2 由 ThreadSample 线程调用,因此 func2 被 ThreadSample 线程锁定 func1 由主线程调用,因此 func1 被主线程锁定,当 ThreadSample 想要从 func2 出去它应该去 func1 但 func1 被主线程锁定,当主线程想要从 func1 出去时它应该去 func2 但 func2 被 ThreadSample 线程锁定。那么应该发生死锁吗?我的错在哪里?
  • 如果你没有遇到死锁,那么你应该因为调用彼此的函数而导致堆栈溢出。
  • 只有一个线程(新创建的或主线程)将处理 func1/func2 调用,但不会有任何问题。
  • 不,我不是因为我在 func2 中造成的延迟
  • 死锁(正如刘能所说,如下)至少需要两个不同的锁。死锁是当您有两个或更多线程时,它们都不能做任何事情(例如,获取锁),直到其中一个做某事(例如,释放一个锁)。最简单的情况(有时称为“致命拥抱”)是线程 A 已获得锁 1 并试图获得锁 2,而同时线程 B 已获得锁 2 并试图获得锁 1。线程将释放它已经获得的锁,直到它获得另一个锁,但是两个线程都无法获得另一个锁......

标签: java multithreading thread-safety deadlock synchronized


【解决方案1】:

死锁只有在有多个锁时才会发生。

在这种情况下,func2func1 在同一个 lock 监视器(TestClass 的一个实例)上同步。一旦一个线程获得了这个锁,其他线程将被阻塞,直到它释放锁。


假设main thread已经进入func1,说明它已经获得了锁,其他线程不能同时调用func2。因为fun1fun2 正在使用同一个锁!而在fun1中,这个线程可以调用fun2,因为synchronized块是可重入的。

【讨论】:

    【解决方案2】:

    您可以将func2() 方法替换为sleep,如下所示以锁定testClass 对象:

    public synchronized void func2() throws InterruptedException {
        System.out.println("func2");
        long a = System.nanoTime();
        Thread.sleep(1000000000000L);
        //func1();
    }
    

    现在,threadSample 线程首先获得锁(在启动之后)在func2 内部等待(持有testClass 对象上的锁)因此main 线程甚至不能进入func1() 等待锁定同一个对象。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2012-04-24
      • 1970-01-01
      • 2021-01-24
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-03-22
      相关资源
      最近更新 更多