当前位置: 代码网 > it编程>编程语言>Java > Java中wait()和notify()的正确使用方式

Java中wait()和notify()的正确使用方式

2026年03月23日 Java 我要评论
wait()、notify()、notifyall() 是 object 类 的原生方法,是 java 最早提供的线程间协作机制(属于低级别、重量级的等待/通知机制)。核心规则(必须全部记住,否则 1

wait()notify()notifyall()object 类 的原生方法,是 java 最早提供的线程间协作机制(属于低级别重量级的等待/通知机制)。

核心规则(必须全部记住,否则 100% 会出问题)

必须在 synchronized 块/方法中调用

  • wait()、notify()、notifyall() 都要求当前线程持有同一个对象的监视器锁(monitor)
  • 否则抛出 illegalmonitorstateexception

wait() 会释放锁

  • 调用 wait() 后,当前线程会释放对象锁,进入该对象的等待队列(wait set)

notify() / notifyall() 不释放锁

  • 只是唤醒等待队列中的一个/全部线程,但不立即把锁给被唤醒的线程
  • 只有当前持有锁的线程离开 synchronized 块后,被唤醒的线程才有机会竞争锁

最经典的写法模板(生产级必须这样写)

// 消费者
synchronized (lock) {
    while (conditionnotmet) {           // 必须用 while,不是 if!(防止虚假唤醒)
        lock.wait();                    // 释放锁并等待
    }
    // 条件满足,消费
    doconsume();
}

// 生产者
synchronized (lock) {
    // 生产
    doproduce();
    lock.notify();          // 或 notifyall()
    // 离开 synchronized 块后,被唤醒的线程才有机会抢锁
}

为什么必须用 while 而不是 if?(虚假唤醒经典坑)

虚假唤醒(spurious wakeup):线程可能在没有被 notify 的情况下被系统唤醒(极少见,但 jvm 规范允许)。

// 错误写法(极易出问题)
if (queue.isempty()) {
    lock.wait();   // 被虚假唤醒后,可能直接往下执行,而队列还是空的
}

// 正确写法(生产环境唯一推荐)
while (queue.isempty()) {
    lock.wait();
}

完整经典示例:生产者-消费者(固定大小队列)

import java.util.linkedlist;
import java.util.queue;

public class producerconsumer {

    private final queue<integer> queue = new linkedlist<>();
    private final int max_size = 10;
    private final object lock = new object();

    class producer implements runnable {
        @override
        public void run() {
            try {
                while (true) {
                    synchronized (lock) {
                        while (queue.size() == max_size) {
                            system.out.println("队列已满,生产者等待...");
                            lock.wait();
                        }
                        int item = (int) (math.random() * 100);
                        queue.offer(item);
                        system.out.println("生产: " + item + ",当前大小: " + queue.size());
                        lock.notifyall();  // 唤醒所有等待的消费者
                    }
                    thread.sleep(500); // 模拟生产耗时
                }
            } catch (interruptedexception e) {
                thread.currentthread().interrupt();
            }
        }
    }

    class consumer implements runnable {
        @override
        public void run() {
            try {
                while (true) {
                    synchronized (lock) {
                        while (queue.isempty()) {
                            system.out.println("队列为空,消费者等待...");
                            lock.wait();
                        }
                        int item = queue.poll();
                        system.out.println("消费: " + item + ",当前大小: " + queue.size());
                        lock.notifyall();  // 唤醒可能等待的生产者
                    }
                    thread.sleep(800); // 模拟消费耗时
                }
            } catch (interruptedexception e) {
                thread.currentthread().interrupt();
            }
        }
    }

    public static void main(string[] args) {
        producerconsumer pc = new producerconsumer();
        new thread(pc.new producer(), "生产者-1").start();
        new thread(pc.new consumer(), "消费者-1").start();
        new thread(pc.new consumer(), "消费者-2").start();
    }
}

常见错误写法汇总(你几乎一定会踩)

错误写法后果正确做法
在 synchronized 外面调用 wait()illegalmonitorstateexception必须在 synchronized 内
用 if 判断条件而不是 while虚假唤醒导致逻辑错误永远用 while
只用 notify() 而不用 notifyall()可能导致部分线程永久等待(信号丢失)多消费者/生产者场景用 notifyall
notify() 后立即修改共享变量可能导致被唤醒线程看到旧状态修改完再 notify
不同对象上 wait/notify线程永远唤不醒必须用同一个锁对象

2025–2026 年真实项目中的选择建议

场景推荐工具原因
简单生产者-消费者、线程间状态等待wait/notify轻量、无额外依赖
需要超时等待condition.await(long, timeunit)reentrantlock 的 condition 更灵活
大多数现代业务代码blockingqueue(arrayblockingqueue)封装好了 wait/notify,api 更安全
高并发、复杂条件等待condition + reentrantlock支持多个等待队列、公平锁、可中断
响应式/异步场景completablefuture / reactor基本不再用原始 wait/notify

一句话总结(面试/生产最常问的答案):

“wait() 和 notify() 必须在同一个对象的 synchronized 块中使用,wait() 会释放锁并进入等待队列,notify() 只唤醒但不释放锁,永远用 while 判断条件,多线程协作场景优先考虑 notifyall()。”

以上就是java中wait()和notify()的正确使用方式的详细内容,更多关于java使用wait()和notify()的资料请关注代码网其它相关文章!

(0)

相关文章:

版权声明:本文内容由互联网用户贡献,该文观点仅代表作者本人。本站仅提供信息存储服务,不拥有所有权,不承担相关法律责任。 如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 2386932994@qq.com 举报,一经查实将立刻删除。

发表评论

验证码:
Copyright © 2017-2026  代码网 保留所有权利. 粤ICP备2024248653号
站长QQ:2386932994 | 联系邮箱:2386932994@qq.com