You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何解决Java死锁问题并让两个线程正常执行?能否用wait/notify实现?

解决Java死锁问题并实现线程正常执行

嘿,你写的这段代码确实触发了经典的循环等待死锁:线程t1持有lock1并等待lock2,线程t2持有lock2并等待lock1,两者都不肯释放手里的锁,直接卡住了。下面给你几种实用的解决方案,包括你问的wait/notify实现方式。

一、最简单的解决方法:统一锁的获取顺序

死锁的核心诱因之一就是线程获取锁的顺序不一致,只要让两个线程都按照相同的顺序获取锁(比如先拿lock1,再拿lock2),就能彻底避免死锁。

修改后的代码:

class MyCode {
    public static Object lock1 = new Object();
    public static Object lock2 = new Object();

    public static void main(String[] args) throws Exception {
        Thread t1 = new Thread(() -> {
            synchronized (lock1) {
                System.out.println("Took lock on object" + lock1);
                try {
                    Thread.sleep(1000); // 缩短睡眠时长方便快速测试
                } catch (Exception e) {}
                synchronized (lock2) {
                    System.out.println("hello world 1....");
                }
            }
        });

        Thread t2 = new Thread(() -> {
            // 这里改成和t1一致的锁获取顺序:先lock1,再lock2
            synchronized (lock1) {
                System.out.println("Took lock on object" + lock1);
                try {
                    Thread.sleep(1000);
                } catch (Exception e) {}
                synchronized (lock2) {
                    System.out.println("hello world 2....");
                }
            }
        });

        t1.start();
        t2.start();
        System.out.println("Hello Java");
    }
}

这样两个线程会依次获取lock1,再获取lock2,绝不会出现互相等待对方锁的情况。

二、使用显式锁(ReentrantLock)的tryLock避免死锁

如果业务场景不允许统一锁顺序,可以用ReentrantLock的tryLock(long timeout, TimeUnit unit)方法,在指定时间内获取不到锁就主动放弃,避免一直阻塞。

示例代码:

import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.ReentrantLock;

class MyCode {
    public static ReentrantLock lock1 = new ReentrantLock();
    public static ReentrantLock lock2 = new ReentrantLock();

    public static void main(String[] args) throws Exception {
        Thread t1 = new Thread(() -> {
            try {
                if (lock1.tryLock(1, TimeUnit.SECONDS)) {
                    System.out.println("Took lock on object" + lock1);
                    try {
                        Thread.sleep(1000);
                        // 尝试获取lock2,超时就放弃并释放已持有的lock1
                        if (lock2.tryLock(1, TimeUnit.SECONDS)) {
                            try {
                                System.out.println("hello world 1....");
                            } finally {
                                lock2.unlock();
                            }
                        } else {
                            System.out.println("t1 failed to get lock2, releasing lock1");
                        }
                    } finally {
                        lock1.unlock();
                    }
                }
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
            }
        });

        Thread t2 = new Thread(() -> {
            try {
                if (lock2.tryLock(1, TimeUnit.SECONDS)) {
                    System.out.println("Took lock on object" + lock2);
                    try {
                        Thread.sleep(1000);
                        if (lock1.tryLock(1, TimeUnit.SECONDS)) {
                            try {
                                System.out.println("hello world 2....");
                            } finally {
                                lock1.unlock();
                            }
                        } else {
                            System.out.println("t2 failed to get lock1, releasing lock2");
                        }
                    } finally {
                        lock2.unlock();
                    }
                }
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
            }
        });

        t1.start();
        t2.start();
        System.out.println("Hello Java");
    }
}

这种方式更灵活,线程不会无限等待锁,超时后会释放已持有的锁,从根源上避免死锁。

三、使用wait/notify实现线程协调

当然可以用wait/notify来解决这个问题!核心思路是通过等待通知机制,让两个线程协调获取锁的时机,避免同时持有对方需要的锁。

我们可以引入一个共享的监视器对象,让线程t1在获取lock1后,等待t2获取lock2并发出通知,再尝试获取lock2;反之亦然。示例代码如下:

class MyCode {
    public static Object lock1 = new Object();
    public static Object lock2 = new Object();
    // 共享监视器,用于wait/notify的同步
    public static Object monitor = new Object();
    // 标记t2是否已获取lock2
    public static boolean t2GotLock2 = false;

    public static void main(String[] args) throws Exception {
        Thread t1 = new Thread(() -> {
            synchronized (lock1) {
                System.out.println("Took lock on object" + lock1);
                try {
                    Thread.sleep(1000);
                    // 等待t2获取lock2的通知,用while循环避免虚假唤醒
                    synchronized (monitor) {
                        while (!t2GotLock2) {
                            monitor.wait();
                        }
                    }
                    // 此时t2已持有lock2,安全获取lock2
                    synchronized (lock2) {
                        System.out.println("hello world 1....");
                    }
                } catch (Exception e) {
                    Thread.currentThread().interrupt();
                }
            }
        });

        Thread t2 = new Thread(() -> {
            synchronized (lock2) {
                System.out.println("Took lock on object" + lock2);
                try {
                    Thread.sleep(1000);
                    // 通知t1:我已经拿到lock2了
                    synchronized (monitor) {
                        t2GotLock2 = true;
                        monitor.notify();
                    }
                    // 安全获取lock1
                    synchronized (lock1) {
                        System.out.println("hello world 2....");
                    }
                } catch (Exception e) {
                    Thread.currentThread().interrupt();
                }
            }
        });

        t1.start();
        t2.start();
        System.out.println("Hello Java");
    }
}

注意:wait/notify必须在同步块中调用,而且要用while循环检查条件(避免JVM的虚假唤醒)。这个例子中,两个线程通过监视器对象协调锁的获取时机,彻底避免了死锁。

内容的提问来源于stack exchange,提问作者Nicky

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.13 08:34:43