Java并发编程:等待唤醒机制

等待通知:wait()/notify()/notifyAll()

这几个方法是Object类中的方法,业务代码中基本不使用。了解即可。

wait()方法

调用该方法的线程会释放共享资源(释放获取的锁),从运行状态进入阻塞状态。wait()方法进行了重载

  • wait():线程进入阻塞状态之后,等待被唤醒。

  • wait(long timeout):进入阻塞状态后,等待一段时间,如果没有被通知唤醒,会自动进入就绪状态。

  • wait(long timeout, int nanos):超时时间为纳秒。

notify()方法

随机唤醒等待队列中等待同一共享资源的1个线程,并使该线程退出等待队列,进入可运行状态。

notifyAll()方法

使所有正在等待队列中等待同一共享资源的全部线程退出等待队列,进入可运行状态。此时优先级最高的那个线程最先执行,但也有可能是随机执行,取决于JVM虚拟机的实现?

相关面试题目

sleep()方法和wait()方法对比

写两个线程,一个线程打印1-52,另一个线程打印A-Z,打印结果为12A34B...5152Z

java 复制代码
class Print {

    private int flag = 1;//信号量。当值为1时打印数字,当值为2时打印字母
    private int count = 1;

    public synchronized void printNum() {
        if (flag != 1) {
            //打印数字
            try {
                // wait使当前线程阻塞,前提是必须获得锁,所以只能在synchronized范围内使用
                wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        System.out.print(2 * count - 1);
        System.out.print(2 * count);
        flag = 2;
        notify();
    }

    public synchronized void printChar() {
        if (flag != 2) {
            //打印字母
            try {
                wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        System.out.print((char) (count - 1 + 'A'));
        count++;//当一轮循环打印完之后,计数器加1
        flag = 1;
        notify();
    }
}

public class Test {
    public static void main(String[] args) {
        Print print = new Print();
        new Thread(() -> {
            for (int i = 0; i < 26; i++) {
                print.printNum();
            }
        }).start();
        new Thread(() -> {
            for (int i = 0; i < 26; i++) {
                print.printChar();
            }
        }).start();
    }
}
  • 共同点:两者都可以暂停线程的执行

  • 区别

    • sleep()方法没有释放锁,wait()方法释放了锁

    • wait()通常被用于线程间交互or通信,sleep()通常被用于暂停执行

    • wait()方法被调用后,线程不会自动苏醒,需要别的线程调用同一个对象上的notify()或者notifyAll()方法。sleep方法执行完成后,线程会自动苏醒,或者也可以使用wait(long timeout)超时后线程会自动苏醒

    • sleep()是Thread类的静态本地方法,wait()是Object类的本地方法。

为什么 wait() 方法不定义在 Thread 中?

wait() 是让获得对象锁的线程实现等待,会自动释放当前线程占有的对象锁。每个对象(Object)都拥有对象锁,既然要释放当前线程占有的对象锁并让其进入 WAITING 状态,自然是要操作对应的对象(Object)而非当前的线程(Thread)。

类似的问题:为什么 sleep() 方法定义在 Thread 中?

因为 sleep() 是让当前线程暂停执行,不涉及到对象类,也不需要获得对象锁。

可以直接调用 Thread 类的 run 方法吗?

这是另一个非常经典的 Java 多线程面试问题,而且在面试中会经常被问到。很简单,但是很多人都会答不上来!

new 一个 Thread,线程进入了新建状态。调用 start()方法,会启动一个线程并使线程进入了就绪状态,当分配到时间片后就可以开始运行了。 start() 会执行线程的相应准备工作,然后自动执行 run() 方法的内容,这是真正的多线程工作。 但是,直接执行 run() 方法,会把 run() 方法当成一个 main 线程下的普通方法去执行,并不会在某个线程中执行它,所以这并不是多线程工作。

总结:调用 start() 方法方可启动线程并使线程进入就绪状态,直接执行 run() 方法的话不会以多线程的方式执行。

参考文章

  1. 彻底搞懂Java的等待-通知(wait-notify)机制
  2. 这几种等待唤醒机制【面试必问】你知道吗
  3. JavaGuide面试题
相关推荐
Spider Cat 蜘蛛猫5 小时前
Springboot SSO系统设计文档
java·spring boot·后端
zyk_computer7 小时前
AI 时代,或许 Rust 比 Python 更合适
人工智能·后端·python·ai·rust·ai编程·vibe coding
Wilber的技术分享7 小时前
【大模型面试八股 3】大模型微调技术:LoRA、QLoRA等
人工智能·深度学习·面试·lora·peft·qlora·大模型微调
雨辰AI7 小时前
SpringBoot3 项目国产化改造完整流程|从 MySQL 到人大金仓落地
java·数据库·后端·mysql·政务
GreenTea8 小时前
【Rust 2026教程:从零构建 Mini-OLAP 引擎】第 6 章 Benchmark 与优化路线图
后端
Rust语言中文社区8 小时前
【Rust日报】2026-05-14 Pyrefly v1.0 正式发布:快速的 Python 类型检查器和语言服务器
开发语言·后端·python·rust
GreenTea9 小时前
【Rust 2026教程:从零构建 Mini-OLAP 引擎】第 5 章 SQL → 逻辑计划 → 物理计划
后端
GreenTea9 小时前
【Rust 2026教程:从零构建 Mini-OLAP 引擎】第 4 章 哈希聚合:GROUP BY 的核心
后端
IT_陈寒9 小时前
Vue的v-for为什么不加key也能工作?我差点翻车
前端·人工智能·后端
GreenTea9 小时前
【Rust 2026教程:从零构建 Mini-OLAP 引擎】第 3 章 表达式系统:把 SQL 表达式变成可执行树
后端