千家信息网

java的wait/notify/notifyAll方法怎么正确使用

发表于:2026-10-31 作者:千家信息网编辑
千家信息网最后更新 2026年10月31日,本篇内容介绍了"java的wait/notify/notifyAll方法怎么正确使用"的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希
千家信息网最后更新 2026年10月31日java的wait/notify/notifyAll方法怎么正确使用

本篇内容介绍了"java的wait/notify/notifyAll方法怎么正确使用"的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!

一:为什么 wait 必须在 synchronized 保护的同步代码中使用?

源码中对wait方法的介绍如下:

        /**         * As in the one argument version, interrupts and spurious wakeups are         * possible, and this method should always be used in a loop:         * 
         *     synchronized (obj) {         *         while (<condition does not hold>)         *             obj.wait();         *         ... // Perform action appropriate to condition         *     }         * 
* This method should only be called by a thread that is the owner * of this object's monitor. See the {@code notify} method for a * description of the ways in which a thread can become the owner of * a monitor. * */ public final void wait() throws InterruptedException { wait(0); }

意思是说,在使用 wait 方法时,必须把 wait 方法写在 synchronized 保护的 while 代码块中,并始终判断执行条件是否满足,如果满足就往下继续执行,如果不满足就执行 wait 方法,而在执行 wait 方法之前,必须先持有对象的 monitor 锁,也就是通常所说的 synchronized 锁。

1.1 不这样做会导致什么问题?

    class BlockingQueue{        Queue buffer = new LinkedList<>();        public void give(String data){            buffer.add(data);            notify();        }        public String take() throws InterruptedException {            while(buffer.isEmpty()){                wait();            }            return buffer.remove();        }    }

在代码中可以看到有两个方法,give 方法负责往 buffer 中添加数据,添加完之后执行 notify 方法来唤醒之前等待的线程,而 take 方法负责检查整个 buffer 是否为空,如果为空就进入等待,如果不为空就取出一个数据,这是典型的生产者消费者的思想。

在如上所示的代码中没有正确使用wait()方法,那么可能出现什么异常呢?

  1. 首先,消费者线程调用 take 方法并判断 buffer.isEmpty 方法是否返回 true,若为 true 代表buffer是空的,则线程希望进入等待,但是在线程调用 wait 方法之前(while(buffer.isEmpty())之后),就被调度器暂停了,所以此时还没来得及执行 wait 方法。

  2. 此时生产者开始运行,执行了整个 give 方法,它往 buffer 中添加了数据,并执行了 notify 方法,但 notify 并没有任何效果,因为消费者线程的 wait 方法没来得及执行,所以没有线程在等待被唤醒。

  3. 此时,刚才被调度器暂停的消费者线程回来继续执行 wait 方法并进入了等待,这时消费者便有可能陷入无穷无尽的等待,因为它错过了刚才 give 方法内的 notify 的唤醒。

ps:上面说的调度器暂停线程,因为在多线程下,CPU 的调度是以时间片为单位进行分配的,每个线程都可以得到一定量的时间片。但如果线程拥有的时间片耗尽,它将会被暂停执行并让出 CPU 资源给其他线程。而代码中的"判断-执行"不是一个原子操作,它在中间有可能被打断,是线程不安全的,所以说有可能在线程调用 wait 方法之前这个线程就被暂停了。

1.2 wait()方法正确使用方式

    class BlockingQueue{        Queue buffer = new LinkedList<>();        public void give(String data){            synchronized (this){                buffer.add(data);                notify();            }        }        public String take() throws InterruptedException {            synchronized (this){                while(buffer.isEmpty()){                    wait();                }                return buffer.remove();            }        }    }

这样就可以确保 notify 方法永远不会在 buffer.isEmpty 和 wait 方法之间被调用,提升了程序的安全性。另外,wait 方法会释放 monitor 锁,这也要求我们必须首先进入到 synchronized 内持有这把锁。

1.2.1 使用while结构判断可以避免虚假唤醒问题

线程可能在既没有被notify/notifyAll,也没有被中断或者超时的情况下被唤醒,这种唤醒是我们不希望看到的。然在实际生产中,虚假唤醒发生的概率很小,但是程序依然需要保证在发生虚假唤醒的时候的正确性,所以就需要采用while循环的结构。

while (condition does not hold)    obj.wait();

这样即便被虚假唤醒了,也会再次检查while里面的条件,如果不满足条件,就会继续wait,也就消除了虚假唤醒的风险。

二:wait 和 sleep 方法的异同

2.1 相同点

  • 它们都可以让线程阻塞

  • 它们都可以响应 interrupt 中断:在等待的过程中如果收到中断信号,都可以进行响应,并抛出 InterruptedException 异常。

2.2 不同点

  1. wait 方法必须在 synchronized 保护的代码中使用,而 sleep 方法并没有这个要求。

  2. 在同步代码中执行 sleep 方法时,并不会释放 monitor 锁,但执行 wait 方法时会主动释放 monitor 锁。

  3. sleep 方法中会要求必须定义一个时间,时间到期后会主动恢复,而对于没有参数的 wait 方法而言,意味着永久等待,直到被中断或被唤醒才能恢复,它并不会主动恢复。

  4. wait/notify/notifyAll 被定义在 Object 类中,而 sleep 定义在 Thread 类中。

2.2.1 为什么wait/notify/notifyAll 被定义在 Object 类中,而 sleep 定义在 Thread 类中?

首先因为 Java 中每个对象都有一把称之为 monitor 监视器的锁,每个对象都可以上锁,在对象头中有一个用来保存锁信息的位置。这个锁是对象级别的,而非线程级别的,wait/notify/notifyAll 也都是锁级别的操作,它们的锁属于对象,所以把它们定义在 Object 类中是最合适,因为 Object 类是所有对象的父类。

其次,一个线程可能持有多把锁,以便实现相互配合的复杂逻辑,既然我们是让当前线程去等待某个对象的锁,自然应该通过操作对象来实现,而不是操作线程。

"java的wait/notify/notifyAll方法怎么正确使用"的内容就介绍到这里了,感谢大家的阅读。如果想了解更多行业相关的知识可以关注网站,小编将为大家输出更多高质量的实用文章!

方法 线程 对象 代码 虚假 时间 消费者 消费 调度 数据 条件 级别 保护 生产 安全 会主 内容 实际 情况 更多 数据库的安全要保护哪些东西 数据库安全各自的含义是什么 生产安全数据库录入 数据库的安全性及管理 数据库安全策略包含哪些 海淀数据库安全审计系统 建立农村房屋安全信息数据库 易用的数据库客户端支持安全管理 连接数据库失败ssl安全错误 数据库的锁怎样保障安全 科技互联网公司装修 科技与互联网发展 亿策互联网科技 四川狮子座互联网科技 科技大学互联网专业好不好 海南科技产业互联网平台 华中科技有哪些互联网大佬 博兴的互联网电子科技公司 广州慧亚互联网科技怎么样 来此购互联网科技有限公司 健康食品互联网创新科技园项目 浙南科技城互联网大厦建设工程 无锡工业互联网科技有限公司 合肥互联网科技公司公章图片 互联网第三次科技革命特征 黑云互联网科技有限公司 卡尔迅互联网科技有限公司 吉林省码上互联网科技电话 广州智享互联网科技 瑞安市蟠桃会互联网科技有限公司 花魁咖啡 智能科技公司是互联网公司吗 礼当家互联网科技 互联网女皇 腾讯科技 互联网科技素材视频竖屏 海南科技产业互联网平台 蓝色互联网科技 互联网 科技馆 科技与互联网哪个更好 盐城市攀科互联网科技有限公司
0