You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

如何在Java中使用wait/notify同步操作不同对象的两个线程?

如何在Java中使用wait/notify同步操作不同对象的两个线程?

兄弟,我懂你现在的困惑——想让两个线程按指定顺序输出,但对着wait/notify有点摸不着头脑对吧?咱们先理清你要的目标顺序:先线程1打den,然后线程2打den,接着线程1打ada,最后线程2打ada。核心就是用两个锁对象(den和ada)来做信号传递,让线程之间互相“打招呼”,告诉对方“我做完了,该你了”。

先说说你之前代码的问题:线程2一上来就死等ada的唤醒,但根本没人去通知它;而且线程1的逻辑也没对齐,没等线程2完成den的打印就直接走了,自然出不来你要的顺序。

给你改好的代码,咱们一步步拆解:

class MyThreads {
    public final static Object den = new Object();
    public final static Object ada = new Object();

    public static Thread t1 = new Thread() {
        public void run() {
            // 第一步:线程1先打印den
            System.out.println("Thread 1 den");
            
            // 通知线程2:我den打完了,你可以打了
            synchronized (den) {
                den.notify();
            }
            
            // 线程1等一等,等线程2打完den再打ada
            synchronized (ada) {
                try {
                    ada.wait();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            
            // 线程1打印ada
            System.out.println("Thread 1 ada");
            
            // 通知线程2:我ada打完了,该你了
            synchronized (ada) {
                ada.notify();
            }
        }
    };

    public static Thread t2 = new Thread() {
        public void run() {
            // 线程2先等着,等线程1打完den再动
            synchronized (den) {
                try {
                    den.wait();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            
            // 线程2打印den
            System.out.println("Thread 2 den");
            
            // 通知线程1:我den打完了,你可以打ada了
            synchronized (ada) {
                ada.notify();
            }
            
            // 线程2等一等,等线程1打完ada再打自己的ada
            synchronized (ada) {
                try {
                    ada.wait();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            
            // 线程2打印ada
            System.out.println("Thread 2 ada");
        }
    };
}

咱们走一遍执行流程,你就懂了:

  1. 两个线程启动后,线程2会先钻进synchronized(den)块调用wait(),释放den的锁,进入等待状态;
  2. 线程1拿到CPU时间,先打印"Thread 1 den",然后进入den的同步块,调用notify()唤醒线程2,之后自己钻进ada的同步块调用wait(),释放ada的锁,开始等;
  3. 被唤醒的线程2继续执行,打印"Thread 2 den",然后进入ada的同步块调用notify()唤醒线程1,接着自己又钻进ada的同步块调用wait()等通知;
  4. 被唤醒的线程1打印"Thread 1 ada",再调用notify()唤醒线程2,然后线程1结束;
  5. 最后线程2被唤醒,打印"Thread 2 ada",完成所有流程。

这里有几个必须注意的点,踩坑了就会出问题:

  • wait()notify()必须在同一个对象的同步块/方法里调用,不然会直接抛异常;
  • 调用wait()的时候,线程会自动释放当前持有的对象锁,不然其他线程根本拿不到锁来唤醒它;
  • 如果有多个线程等同一个对象,建议用notifyAll()代替notify(),避免唤醒错线程,不过咱们这里只有两个线程,用notify()没问题。

备注:内容来源于stack exchange,提问作者pure21_h

火山引擎 最新活动