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

Java多线程同步问题:仅用wait/notify实现线程互斥运行

用wait()/notify()实现线程互斥执行的解决方案

看起来你在尝试用wait/notify实现线程间的互斥执行,核心问题出在锁的共享性和条件控制的逻辑上。我来帮你拆解问题,然后给出可运行的修正方案。

你的代码存在的关键问题

  • 锁不共享:把synchronized加在run()方法上是无效的——每个线程对象的run()方法锁的是线程实例本身,多个线程的锁完全独立,根本无法阻止其他线程同时执行。
  • 控制变量不共享:如果lock是每个线程自己的成员变量,那它无法全局控制所有线程的执行状态,必须是所有线程共用的变量。
  • 未正确唤醒线程:任务执行完后没有重置控制标记,也没有调用notify()/notifyAll(),导致其他线程会一直卡在wait()中无法唤醒。

正确的实现方案

我们需要一个共享的锁对象让所有线程同步,再用一个共享的状态变量标记当前允许运行的线程类型,每个线程在执行前先检查状态,不符合就等待;执行完任务后切换状态并唤醒其他等待的线程。

完整代码示例

// 共享控制类:管理线程的执行状态和锁
class CarControl {
    // 标记当前允许运行的方向(Left/Right)
    private String currentDirection;
    // 全局共享锁对象,所有线程共用这一个锁
    private final Object lock = new Object();

    public CarControl(String initialDirection) {
        this.currentDirection = initialDirection;
    }

    // 左侧车辆执行逻辑
    public void runLeftCar(String leftMessage) throws InterruptedException {
        synchronized (lock) {
            // 用while循环判断条件,防止虚假唤醒
            while (!"Left".equals(currentDirection)) {
                lock.wait();
            }
            // 执行左侧任务
            System.out.println("LeftSideCar: " + leftMessage);
            System.out.println("State: Left");
            // 这里可以调用你的Direction()方法
            // Direction();
            // 任务完成后切换方向,唤醒所有等待的线程
            currentDirection = "Right";
            lock.notifyAll();
        }
    }

    // 右侧车辆执行逻辑
    public void runRightCar(String rightMessage) throws InterruptedException {
        synchronized (lock) {
            while (!"Right".equals(currentDirection)) {
                lock.wait();
            }
            // 执行右侧任务
            System.out.println("RightSideCar: " + rightMessage);
            System.out.println("State: Right");
            // Direction();
            // 切换方向并唤醒所有线程
            currentDirection = "Left";
            lock.notifyAll();
        }
    }
}

// 左侧线程类
class LeftCarThread extends Thread {
    private final CarControl control;
    private final String message;

    public LeftCarThread(CarControl control, String message) {
        this.control = control;
        this.message = message;
    }

    @Override
    public void run() {
        try {
            // 模拟多次执行任务,可根据需求调整
            for (int i = 0; i < 3; i++) {
                control.runLeftCar(message + " - 第" + (i+1) + "次");
                // 模拟任务间隔,可选
                Thread.sleep(500);
            }
        } catch (InterruptedException e) {
            // 正确处理中断:恢复中断状态
            Thread.currentThread().interrupt();
            System.out.println("左侧车辆线程被中断");
        }
    }
}

// 右侧线程类
class RightCarThread extends Thread {
    private final CarControl control;
    private final String message;

    public RightCarThread(CarControl control, String message) {
        this.control = control;
        this.message = message;
    }

    @Override
    public void run() {
        try {
            for (int i = 0; i < 3; i++) {
                control.runRightCar(message + " - 第" + (i+1) + "次");
                Thread.sleep(500);
            }
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
            System.out.println("右侧车辆线程被中断");
        }
    }
}

// 测试主类
public class LeftRightCarTest {
    public static void main(String[] args) {
        // 初始允许左侧车辆先运行
        CarControl control = new CarControl("Left");
        LeftCarThread leftThread = new LeftCarThread(control, "左转通行");
        RightCarThread rightThread = new RightCarThread(control, "右转通行");

        leftThread.start();
        rightThread.start();
    }
}

核心要点解释

  1. 共享锁对象:所有线程都使用CarControl中的lock对象进行同步,确保同一时间只有一个线程进入同步块,实现互斥。
  2. while循环判断条件:必须用while而非if检查状态,因为wait()可能被虚假唤醒(其他线程调用notifyAll()但当前线程的执行条件仍不满足),每次唤醒后都要重新验证条件。
  3. 任务完成后唤醒线程:执行完自身任务后,更新状态并调用notifyAll(),唤醒所有等待的线程,让符合条件的线程继续执行。
  4. 正确处理中断:当线程被中断时,恢复中断状态并做必要的清理,避免线程状态异常。

注意事项

  • 调用wait()、notify()、notifyAll()必须在synchronized块/方法内,且针对同一个锁对象。
  • 永远不要在if语句中调用wait(),虚假唤醒是线程编程中常见的场景,必须用while循环处理。
  • 共享变量(比如currentDirection)不需要额外加volatile,因为它的读写都在synchronized块内,已经保证了可见性。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.27 03:28:25