Java 线程的 await 和 wait 的实现

在 Java 中,线程的协调和通信是一个重要的主题。wait()notify() 方法使得线程可以在某些情况下暂停执行,待一定条件满足后再继续执行。下面,我将一步步教你如何实现这个过程。

流程概述

在实现线程的等待与唤醒机制时,主要的流程可以概括为以下几点:

步骤 描述
1 创建一个共享对象
2 创建线程并实现 run() 方法
3 在线程中调用 wait() 方法
4 调用 notify()notifyAll()
5 线程在适当的时候继续执行

每一步的实现

步骤 1:创建一个共享对象

我们首先需要一个共享对象。在这个例子中,我们会创建一个简单的类,它包含一个可以被等待的状态。

public class SharedObject {
    // 当前状态
    private boolean isReady = false;

    // 获取状态
    public synchronized boolean isReady() {
        return isReady;
    }

    // 设置状态并通知等待的线程
    public synchronized void setReady() {
        isReady = true;
        notify();  // 唤醒等待的线程
    }
}

注释:在以上代码中,SharedObject 类包含一个布尔字段 isReady,用于表示状态。它有两个同步的方法,一个用于获取状态,另一个用于设置并通知等待的线程。

步骤 2:创建线程并实现 run() 方法

然后,我们创建两个线程,一个用于设置状态,另一个用于等待状态改变。

public class WaitThread extends Thread {
    private final SharedObject sharedObject;

    public WaitThread(SharedObject sharedObject) {
        this.sharedObject = sharedObject;
    }

    @Override
    public void run() {
        synchronized (sharedObject) {
            while (!sharedObject.isReady()) {
                try {
                    System.out.println("线程 " + Thread.currentThread().getName() + " 正在等待...");
                    sharedObject.wait();  // 等待状态改变
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            System.out.println("线程 " + Thread.currentThread().getName() + " 状态已改变,继续执行!");
        }
    }
}

注释WaitThread 类继承自 Thread,在其 run() 方法中,它会反复检查状态。如果状态未准备好,通过 wait() 方法等待状态改变。

步骤 3:在线程中调用 wait() 方法

上面的代码已经在 run() 方法中实现了 wait() 调用。当 wait() 被调用时,当前线程会释放锁并暂停执行,直到被其他线程唤醒。

步骤 4:调用 notify()

创建另一个线程,负责设置状态并通知等待的线程:

public class NotifyThread extends Thread {
    private final SharedObject sharedObject;

    public NotifyThread(SharedObject sharedObject) {
        this.sharedObject = sharedObject;
    }

    @Override
    public void run() {
        try {
            Thread.sleep(2000); // 模拟一些工作
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        sharedObject.setReady(); // 设置状态为 ready
        System.out.println("线程 " + Thread.currentThread().getName() + " 设置状态为 ready!");
    }
}

注释NotifyThread 线程会在睡眠 2 秒后设置状态为 ready,并调用 notify() 方法唤醒等待的线程。

步骤 5:线程继续执行

当状态改变时,被唤醒的线程会继续执行其后续代码。

运行示例

现在我们将所有的类结合在一个主程序中,并运行它们:

public class Main {
    public static void main(String[] args) {
        SharedObject sharedObject = new SharedObject();

        // 创建等待线程
        WaitThread waitThread = new WaitThread(sharedObject);
        waitThread.start();

        // 创建通知线程
        NotifyThread notifyThread = new NotifyThread(sharedObject);
        notifyThread.start();
    }
}

注释:在 main 方法中,我们创建 SharedObject 实例,并启动等待和通知线程。

关系图

接下来我们使用 Mermaid 语法表示线程与共享对象之间的关系:

erDiagram
    THREAD {
        string name "线程名称"
    }
    SHARED_OBJECT {
        boolean isReady "当前状态"
    }
    THREAD ||--o{ SHARED_OBJECT : waits_on

数据分布

使用 Mermaid 的饼状图表示线程状态:

pie
    title 线程状态分布
    "等待状态": 70
    "运行状态": 30

结尾

通过上述步骤,您已经了解了如何在 Java 中使用 wait()notify() 来实现线程间的等待与唤醒。请记住,wait() 必须在同步代码块中使用,否则会抛出 IllegalMonitorStateException。使用得当,可以有效控制线程的执行顺序,同时避免死锁和资源浪费。

如果你对线程的其它特性有兴趣,不妨继续深入学习,例如使用 SemaphoreCountDownLatch 等其他同步工具。