跳转到内容

Java notify方法

来自代码酷

Java notify方法[编辑 | 编辑源代码]

notify() 是 Java 多线程编程中的一个核心方法,用于线程间通信。它是 Object 类的一个方法,用于唤醒在该对象监视器(锁)上等待的单个线程。该方法通常与 wait() 方法配合使用,实现线程的协调与同步。

介绍[编辑 | 编辑源代码]

在 Java 中,线程可以通过调用对象的 `wait()` 方法进入等待状态,释放对象的锁。其他线程可以通过调用同一个对象的 `notify()` 或 `notifyAll()` 方法来唤醒等待的线程。`notify()` 方法会随机唤醒一个等待的线程,而 `notifyAll()` 会唤醒所有等待的线程。

`notify()` 方法必须在同步代码块或同步方法中调用,否则会抛出 IllegalMonitorStateException

语法[编辑 | 编辑源代码]

public final void notify()

使用示例[编辑 | 编辑源代码]

以下是一个简单的生产者-消费者模型示例,展示 `wait()` 和 `notify()` 的典型用法:

class SharedResource {
    private int value;
    private boolean available = false;

    public synchronized void produce(int newValue) {
        while (available) {
            try {
                wait(); // 等待消费者消费
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
            }
        }
        value = newValue;
        available = true;
        System.out.println("生产: " + value);
        notify(); // 唤醒消费者线程
    }

    public synchronized int consume() {
        while (!available) {
            try {
                wait(); // 等待生产者生产
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
            }
        }
        available = false;
        System.out.println("消费: " + value);
        notify(); // 唤醒生产者线程
        return value;
    }
}

public class ProducerConsumerExample {
    public static void main(String[] args) {
        SharedResource resource = new SharedResource();

        Thread producer = new Thread(() -> {
            for (int i = 0; i < 5; i++) {
                resource.produce(i);
            }
        });

        Thread consumer = new Thread(() -> {
            for (int i = 0; i < 5; i++) {
                resource.consume();
            }
        });

        producer.start();
        consumer.start();
    }
}

输出示例:

生产: 0
消费: 0
生产: 1
消费: 1
生产: 2
消费: 2
生产: 3
消费: 3
生产: 4
消费: 4

工作原理[编辑 | 编辑源代码]

`notify()` 方法的工作流程可以用以下状态图表示:

stateDiagram [*] --> 线程等待 线程等待 --> 线程唤醒: notify() 线程唤醒 --> 线程运行 线程运行 --> 线程等待: wait()

1. 线程调用 `wait()` 后进入等待状态,释放对象锁 2. 另一个线程获取锁并执行 `notify()` 3. JVM 从等待池中选择一个线程唤醒 4. 被唤醒的线程尝试重新获取锁,成功后继续执行

注意事项[编辑 | 编辑源代码]

  • 虚假唤醒:有时线程可能在没有收到 `notify()` 的情况下被唤醒,因此等待条件应该放在循环中检查
  • 锁的释放:调用 `wait()` 会释放锁,而 `notify()` 不会释放锁,线程会在同步块结束后才释放锁
  • 选择不确定性:`notify()` 唤醒的线程是随机的,不能指定唤醒哪个线程

高级用法[编辑 | 编辑源代码]

对于更复杂的场景,可以使用 `Condition` 接口(来自 `java.util.concurrent.locks` 包)提供更精细的线程控制:

import java.util.concurrent.locks.*;

class AdvancedSharedResource {
    private final Lock lock = new ReentrantLock();
    private final Condition condition = lock.newCondition();
    private int value;
    private boolean available = false;

    public void produce(int newValue) {
        lock.lock();
        try {
            while (available) {
                condition.await();
            }
            value = newValue;
            available = true;
            System.out.println("高级生产: " + value);
            condition.signal();
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
        } finally {
            lock.unlock();
        }
    }

    public int consume() {
        lock.lock();
        try {
            while (!available) {
                condition.await();
            }
            available = false;
            System.out.println("高级消费: " + value);
            condition.signal();
            return value;
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
            return -1;
        } finally {
            lock.unlock();
        }
    }
}

实际应用场景[编辑 | 编辑源代码]

1. 线程池管理:当任务队列为空时,工作线程可以等待,当有新任务加入时唤醒线程 2. 消息队列:消费者线程在没有消息时等待,生产者添加消息后通知消费者 3. 资源池:当资源不可用时线程等待,资源释放后通知等待线程

数学表示[编辑 | 编辑源代码]

线程同步的基本模式可以用以下公式表示: wait()释放锁等待通知获取锁继续执行 notify()选择等待线程标记为可运行

常见问题[编辑 | 编辑源代码]

为什么要在循环中检查等待条件?[编辑 | 编辑源代码]

因为存在虚假唤醒的可能,即线程可能在没有收到通知的情况下被唤醒。循环检查可以确保条件确实满足后再继续执行。

notify() 和 notifyAll() 有什么区别?[编辑 | 编辑源代码]

  • `notify()` 唤醒一个等待线程(选择是随机的)
  • `notifyAll()` 唤醒所有等待线程,它们将竞争锁

如果没有线程在等待时调用 notify() 会怎样?[编辑 | 编辑源代码]

调用会被忽略,不会产生任何效果,也不会抛出异常。

总结[编辑 | 编辑源代码]

`notify()` 是 Java 线程间通信的基本机制之一,与 `wait()` 配合使用可以实现高效的线程协作。理解其工作原理和正确使用方法对于编写可靠的多线程程序至关重要。在实际开发中,应考虑使用更高级的并发工具(如 `java.util.concurrent` 包中的类),但在底层,它们大多基于这些基本的等待/通知机制。