为什么同步方法不能导致死锁

问题描述

我使用synced测试了deadLock,并且发现synced无法通过在方法添加deadLock导致deadLock。这是代码

public static void main(String[] args) {

    DeadLock t1 = new DeadLock();
    DeadLock t2 = new DeadLock();
    new Thread(() -> {
        t1.m1();
    }).start();
    new Thread(() -> {
        t2.m1();
    }).start();


}

synchronized void m1() {
    System.out.println(Thread.currentThread().getName() + ":m1 start");
    try {
        TimeUnit.SECONDS.sleep(10);
    } catch (InterruptedException e) {
        e.printstacktrace();
    }
    System.out.println(Thread.currentThread().getName() + ":m1 waiting to get m2");
    m2();
}

synchronized void m2() {
    System.out.println(Thread.currentThread().getName() + ":m2 start");
    try {
        TimeUnit.SECONDS.sleep(10);
    } catch (InterruptedException e) {
        e.printstacktrace();
    }
    System.out.println(Thread.currentThread().getName() + ":m2 waiting to get m1");
    m1();
}

为什么同步方法不能导致死锁,它总是循环执行。

解决方法

您正在两个不同的实例上调用m1()方法。 synchronized关键字阻止从多个同步块/方法同时访问同一对象Read this

要引起死锁,两个线程应该请求另一个线程当前占用的资源。

此代码将成功陷入死锁!

public class DeadLock {
    public static void main(String[] args) {
        DeadLock t1 = new DeadLock();
        DeadLock t2 = new DeadLock();
        t1.setOther(t2);
        t2.setOther(t1);

        new Thread(() -> {
            t1.m1();
        }).start();
        new Thread(() -> {
            t2.m1();
        }).start();

    }

    private DeadLock other;
    public void setOther(DeadLock other) {
        this.other = other;
    }

    void print(String msg) {
        System.out.println(Thread.currentThread().getName() + msg);
    }

    synchronized void m1() {
        print(":m1 start");
        try {
            TimeUnit.MILLISECONDS.sleep(1);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        print(":m1 waiting to get other.m1");
        other.m1();
    }
}
,

之所以会这样,是因为Java中的隐式对象监视器锁定是 reentrant 。也就是说,如果线程在对象上持有隐式监视器锁,则它将能够执行该锁保护的任何代码段。当线程进入m1()时,它可以输入m2()(反之亦然),因为它已经拥有了锁。这将使广告无限地发生

要演示死锁,您必须使用两种不同的锁来保护这两种方法:

void m1() {
    synchronized(obj1) {
        System.out.println(Thread.currentThread().getName() + ":m1 start");
        try {
            TimeUnit.SECONDS.sleep(10);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println(Thread.currentThread().getName() + ":m1 waiting to get m2");
        m2();
    }
}

void m2() {
    synchronized(obj2) {
        System.out.println(Thread.currentThread().getName() + ":m2 start");
        try {
            TimeUnit.SECONDS.sleep(10);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println(Thread.currentThread().getName() + ":m2 waiting to get m1");
        m1();
    }
}

然后在相同 DeadLock对象上调用这些方法。