Java中notify与notifyAll的核心区别与执行逻辑解析

陈默
陈默
发布时间:2026-10-13| 4人浏览过
原创

本文深入解析Java中notify和notifyAll的异同。重点阐述它们如何影响线程状态转换及后续的锁竞争行为,通过代码示例说明为何调用notifyAll后并非所有被通知线程都能立即执行。

结果或目标:明确唤醒策略的实际效果

在并发编程中,使用Object.wait()、notify()和notifyAll()是为了管理线程间的协作。很多开发者存在一个误区,认为notifyAll会像“广播”一样让所有等待线程同时恢复运行。实际上,这两个方法的核心区别在于唤醒的数量,但后续的执行受到对象监视器(锁)的严格限制。

准备条件:同步环境与方法要求

在使用这些方法前,必须满足以下约束:

  • 所有者限制:只有获得对象监视器(即持有锁)的线程才能调用wait、notify或notifyAll。这通常通过synchronized块或同步方法实现。
  • 状态转移:wait()会导致当前线程放弃锁并进入等待集。notify/notifyAll则是从等待集中移除线程,使其重新进入锁竞争队列。

真实操作顺序:锁竞争机制深度解析

第1步:设置等待环境

定义一个资源对象作为监视器,并创建多个线程进入等待状态。每个线程在获取锁后调用wait()挂起自身。

private static final Object obj = new Object();
static class R implements Runnable {
    int i;
    R(int i) { this.i = i; }
    public void run() {
        try {
            synchronized(obj) {
                System.out.println("线程-> " + i + " 等待中");
                obj.wait(); // 放弃锁并等待
                System.out.println("线程-> " + i + " 在运行了");
                Thread.sleep(30000); // 模拟长时间任务,持有锁
            }
        } catch(Exception e) {
            e.printStackTrace();
        }
    }
}

第2步:触发唤醒操作

主线程启动上述多个工作线程后,短暂休眠以便所有线程进入等待状态,随后在主线程持有的锁内调用notifyAll()。

Thread[] rs = new Thread[10];
for(int i = 0; i < 10; i++) {
    rs[i] = new Thread(new R(i));
}
for(Thread r : rs) {
    r.start();
}
Thread.sleep(5000);
// 主线程获取锁并通知所有等待者
synchronized(obj) {
    obj.notifyAll();
}

第3步:观察锁竞争与执行结果

当notifyAll被调用时,所有处于等待集的线程都被移出,并重新尝试获取obj上的锁。由于synchronized的单线程持有特性,同一时间只能有一个线程成功获得锁。

  • 输出现象:控制台会打印出所有线程“等待中”,但在notifyAll之后,通常只会有一个线程打印“在运行了”。
  • 原因分析:第一个获取到锁的线程开始执行其后的代码(包括sleep(30000))。在此期间,其他被唤醒的线程处于“锁竞争失败”状态,它们在原地排队等待,直到前一个线程释放锁。

完成判断与核心结论

要判断线程是否真正“继续运行”,需满足两个必要条件:

  1. 被notify或notifyAll唤醒(状态从WAITING变为BLOCKED)。
  2. 成功通过竞争获取到对象的监视器锁。

因此,notify和notifyAll在极端情况下可能产生相同的单线程执行效果,但适用场景不同:

  • notify:适用于只需唤醒单一竞争者即可推进任务的场景(如单一生产者-单一消费者),效率高但易丢失唤醒信号。
  • notifyAll:适用于需要所有或多数等待者检查条件并继续处理的场景,虽然引入了额外的锁竞争开销,但能确保不遗漏任何需要响应的线程。

简要总结

理解notify与notifyAll的关键在于区分“唤醒动作”与“锁获取动作”。唤醒只是解除了线程的睡眠状态,让其进入争抢资源的队列;真正的执行权取决于谁能在随后的竞争中获得锁。合理选择两者能有效提升系统的响应性与吞吐量。

以上就是Java notify和NotifyAll的区别的详细内容,更多关于Java线程调度的资料请关注本站其它相关文章!

相关标签:

免责声明:本文内容仅供参考,不代表本站观点。转载或引用请注明出处。

Python 相关产品和应用

全部下载
Selenium

Selenium

4.51.0 · Windows

用于浏览器自动化和 Web 测试的 Python 工具。

scikit-learn

scikit-learn

1.9.1 · Windows

常用 Python 机器学习算法与模型评估工具库。

Black

Black

26.10.1 · Windows

强调一致性的 Python 自动代码格式化工具。

Ruff

Ruff

0.17.1 · macOS

由 Rust 编写的高速 Python 代码检查和格式化工具。

pytest

pytest

9.1.1 · Windows

简洁而强大的 Python 自动化测试框架。

FastAPI

FastAPI

0.146.0 · Windows

高性能 Python API 框架,支持类型提示和自动接口文档。

Flask

Flask

3.1.3 · Windows

轻量灵活的 Python Web 应用框架。

Django

Django

6.1.2 · Windows

成熟的 Python Web 框架,适合构建内容站点和业务系统。

Spyder

Spyder

6.1.7 · Windows

面向科学计算与数据分析的 Python 集成开发环境。

SciPy

SciPy

1.18.1 · Windows

面向科学、工程和技术计算的 Python 算法库。