2

我正在尝试 Java 多线程中的死锁概念。我遇到了一个可能导致死锁的代码片段:

public class Deadlock {
double amount = 10.0;

public double deposit(double d) {
    amount += d;
    return amount;
}

public double withdraw(double d) {
    amount -= d;
    return amount;
}

public static void transfer(Deadlock from, Deadlock to,double d) {
    synchronized(from) {
        synchronized(to) {
            from.withdraw(d);
            try {
                System.out.println(Thread.currentThread().getName());
                Thread.sleep(5000);
            }catch(Exception e){}

            to.deposit(d);
            System.out.println("Done");
        }
    }
}

public static void main(String[] args) {
    final Deadlock a = new Deadlock();
    final Deadlock b = new Deadlock();

    Thread t1 = new Thread(new Runnable() {
        public void run() {
            transfer(a, b, 10.0);
        }
    });
    t1.start();



    Thread t2 = new Thread(new Runnable() {
        public void run() {
            transfer(b, a, 10.0);
        }
    });
    t2.start();
}
}

基本上,代码尝试同时获取对象 a 和 b 上的锁。但是,当我运行它时,代码总是成功完成。为什么不会出现这种僵局?

4

4 回答 4

4

如果一个线程能够同时到达这两个,这完全取决于线程调度程序

synchronized(from) {
    synchronized(to) {

在另一个线程到达第一个线程之前。sleep在它们之间添加一个足够大的

synchronized (from) {
    try {
        Thread.sleep(20L);
    } catch (InterruptedException e1) {
        e1.printStackTrace();
    }
    synchronized (to) {

你应该会遇到死锁。

于 2013-11-03T05:01:32.123 回答
4

为了发生死锁,您需要发生以下情况:

t1 acquires lock a
t2 acquires lock b

t1 attempts to acquire lock b
t2 attempts to acquire lock a

你能强迫这个吗?您可以尝试在锁定获取之间移动您的睡眠语句,但这一切都必须发生在一个不受您直接控制的窗口内。

试试这个:

public static void transfer(DeadLock from, DeadLock to,double d) {
    synchronized(from) {
        try {
            System.out.println(Thread.currentThread().getName() +" acquires lock " +from);
            Thread.sleep(5000);
            synchronized(to) {
                System.out.println(Thread.currentThread().getName() +" acquires lock " +to);
                from.withdraw(d);
                to.deposit(d);
                System.out.println("Done");
            }
        }catch(Exception e){}
    }
}

并确认您处于死锁状态,将SIGQUIT信号发送到您的 Java 进程 - JVM 将报告处于死锁状态的线程

于 2013-11-03T05:01:42.007 回答
2

到达方法传输的第一个线程将快速获取资源(往返),以至于它可能不会与第二个线程交错。话虽如此,这段代码仍然容易出现死锁。下面的代码尝试只获取足够长的第一个锁,以便第二个线程被安排运行:

public static void transfer(Deadlock from, Deadlock to, double d) throws InterruptedException {
    synchronized (from) {
        Thread.sleep(5000);
        synchronized (to) {
            from.withdraw(d);
            System.out.println(Thread.currentThread().getName());
            to.deposit(d);
            System.out.println("Done");
        }
    }
}
于 2013-11-03T05:23:09.310 回答
0

sleeping a Thread does not release the locks it holds, while waiting releases the lock

T1 对两个死锁对象都有锁,即使在睡眠期间,只有当 T1 存在相应的同步锁时,t2 才能访问它。

所以要引入死锁,你需要在同步语句之间休眠。

或者,您也可以尝试代替Thread.sleep(5000); to.wait(5000);

于 2013-11-03T05:01:24.593 回答