无法在嵌套同步的 java 中模拟死锁

Unable to simulate deadlock in java with nested synchronized

提问人:Java_dev_dev 提问时间:10/5/2023 更新时间:10/5/2023 访问量:50

问:

我正在玩 Java 中的线程,并决定模拟死锁情况,但无法做到。

在嵌套的同步块之间添加语句之前,以下代码不会导致死锁情况:

public class Main {

    public static class Account {

        String name;

        AtomicInteger money = new AtomicInteger(0);

        void deposit(final int amount){
            money.addAndGet(amount);
        }

        void withdraw(final int amount){
            money.getAndAdd(-amount);
        }
    }


    public static void main(String[] args) throws ExecutionException, InterruptedException, Exception {
        int n = 5000;
        for (int i = 0; i < n; i++) {
            Thread thread1 = new Thread(() -> transfer(account1, account2, 1));
            Thread thread2 = new Thread(() -> transfer(account2, account1, 2));
            thread1.start();
            thread2.start();
            thread1.join();
            thread2.join();
         
            
        }
    }

    public static void transfer(Account from, Account to, int amount){
        System.out.println("Hello from :" + Thread.currentThread());
        synchronized(from){
         // If bellow line is uncommented deadlock will occur, otherwise not
         // System.out.println();
            synchronized(to){
                from.withdraw(amount);
                to.deposit(amount);
            }
        }
    }
}

根据我的理解,这应该以死锁告终,尤其是在运行模拟 5k 次时,但是在将 n 设置为任意大 int 后,应用程序将成功终止。在两个嵌套的同步语句之间添加简单的 println 语句后:

synchronized(from){
            **System.out.println();**
            synchronized(to){

我陷入了僵局。

我很困惑为什么当同步之间没有语句时它不会发生。我是否遗漏了什么,或者存在一些固有的 Java 机制(优化),如果没有中间语句,它会让一个线程优先于嵌套同步?或者它只是我的机器/JVM/OS 组合?

Java 多线程 模拟 死锁

评论

0赞 Jorn 10/5/2023
最有可能的是,正在发生的 I/O 导致调度程序决定这是切换线程或其他东西的好时机。你绝对不能依赖这种行为。
1赞 aled 10/5/2023
并发问题之所以困难是有原因的。有时你不知道如何有意识地重现它们。
0赞 user207421 10/5/2023
如果以不同的顺序同步对象,则会死锁。如果始终以相同的顺序进行同步,则不会同步。

答:

1赞 Solomon Slow 10/5/2023 #1

据我了解,这应该以僵局告终。

不。它最终可能会陷入僵局,但如果没有这些电话,机会就很小了。当我说“渺茫”时,我说的是那种渺茫的机会;我工作的一家公司对新产品进行了数周的测试,在所有测试通过后,我们将其交付给十几个客户。然后,客户运行了半年,然后其中一个客户的服务器上发生了死锁,中断了他们的电子商务网站。(*我*通过研究他们发回给我们的 4Gb 核心文件来弄清楚发生了什么,这是一项有趣的工作。println

如果没有这些电话,*MUCH*更有可能发生的事情是;任何一个线程在另一个线程有机会尝试之前锁定两个互斥锁,它完成它的工作,然后轮到另一个线程。println