Java中为什么wait,notify 和 notifyAll 在同步块或方法中调用
大多数 Java 开发人员都知道对象类的 wait()
、notify()
和 notifyAll()
方法必须在 Java 中的同步方法或同步块中调用,但我们想过多少次这是为什么? 最近这个问题在 Java 面试中被问到我的一个朋友,他沉思了一下并回答说如果我们不从同步上下文调用 wait()
或 notify()
方法,我们将在 Java 中收到 IllegalMonitorStateException
。 就语言行为而言,他是对的,但根据他的说法,面试官对答案并不完全满意,想向他解释更多。
面试结束后,他和我讨论了同样的问题,我认为他应该告诉面试官关于 Java 中 wait()
和 notify()
之间的竞争条件,如果我们不在同步方法或块中调用它们,它们可能存在。 让我们看看它是如何在 Java 程序中发生的。
这也是流行的线程面试问题之一,在 Java 开发人员的面试中经常被问到。 所以,如果你正在准备 Java 面试,你应该准备这样的问题,
为什么 wait()、notify() 和 notifyAll() 必须从 Java 中的同步块或方法中调用
我们主要使用 wait()
、notify()
或 notifyAll()
方法来进行 Java 中的线程间通信。 一个线程在检查条件后等待,例如 在经典的 Producer-Consumer 问题中,如果缓冲区已满,生产者线程将等待,并且消费者线程在通过消耗元素在缓冲区中创建空间后通知生产者线程。
调用 notify()
或 notifyAll()
方法向单个或多个线程发出条件已更改的通知,一旦通知线程离开同步块,所有正在等待的线程都会争夺它们正在等待的对象锁,并且 幸运线程在重新获取锁后从 wait()
方法返回并继续进行。
让我们将整个操作分成几个步骤来查看 Java 中 wait()
和 notify()
方法之间竞争条件的可能性,我们将使用 Produce Consumer 线程示例来更好地理解该场景:
- Producer 线程测试条件(buffer是否满),确认必须等待(发现buffer满后)。
- Consumer 线程在使用缓冲区中的元素后设置条件。
-
Consumer 线程调用
notify()
方法; 这是闻所未闻的,因为生产者线程尚未等待。 -
Producer 线程调用
wait()
方法,进入等待状态。
因此,由于这里的竞争条件,我们可能会丢失通知,如果我们使用缓冲区或仅使用一个元素,Produce 线程将永远等待,我们的程序将挂起。
现在让我们考虑如何解决这种潜在的竞争条件? 这种竞争条件通过使用 synchronized
关键字和 Java 提供的锁来解决。 为了调用 Java 中的 wait()
、notify()
或 notifyAll()
方法,我们必须已经获得调用方法的对象的锁。
由于 Java 中的 wait()
方法也会在等待之前释放锁并在从 wait()
方法返回之前重新获取锁,因此我们必须使用此锁来确保检查条件(缓冲区是否已满)并设置 条件(从缓冲区中获取元素)是原子的,这可以通过在 Java 中使用同步方法或块来实现。
我不确定这是否是面试官真正期望的,但我认为这至少是有道理的,如果我错了请纠正我,请告诉我们是否还有其他令人信服的调用 wait()
、notify()
的理由 ,或 Java 中的 notifyAll
方法。
总结一下,我们从 Java 中的同步方法或同步块调用 Java 中的 wait()
、notify()
或 notifyAll
方法以避免:
-
Java中的
IllegalMonitorStateException
如果我们不从同步上下文中调用wait()
、notify()
或notifyAll()
方法就会发生。 -
Java 中
wait
和notify
方法之间的任何潜在竞争条件。
相关文章
在 Java 中获取文件大小
发布时间:2023/05/01 浏览次数:139 分类:Java
-
Java 提供了不同的方法来获取文件的字节大小。 本教程演示了在 Java 中获取文件大小的不同方法。使用 Java IO 的文件类获取文件大小 Java IO 包的 File 类提供了以字节为单位获取文件大小的功能。
Java 中的文件分隔符
发布时间:2023/05/01 浏览次数:108 分类:Java
-
本篇文章介绍了 Java 中的文件分隔符。Java 中的文件分隔符 文件分隔符是用来分隔目录的字符; 例如,Unix 使用 /,Windows 使用 \ 作为文件分隔符。
Java 中的文件过滤器
发布时间:2023/05/01 浏览次数:193 分类:Java
-
本篇文章介绍如何在 Java 中使用 FileFilter。FileFilter 用于过滤具有特定扩展名的文件。 Java内置包IO和Apache Commons IO为FileFilter提供了类和接口来进行文件过滤操作。
Java 获取 ISO 8601 格式的当前时间戳
发布时间:2023/05/01 浏览次数:132 分类:Java
-
本篇文章介绍了 ISO 8601 日期格式、其重要性及其在 Java 中的使用。 它还列出了一些优点来强调为什么应该使用 ISO 格式来表示日期。
在 Java 中获取数组的子集
发布时间:2023/05/01 浏览次数:142 分类:Java
-
本篇文章介绍了几种在 Java 中获取数组子集的方法。使用 Arrays.copyOf() 方法获取数组的子集 使用 Arrays.copyOfRange() 方法获取数组的子集
用 Java 填充二维数组
发布时间:2023/05/01 浏览次数:110 分类:Java
-
二维数组是基于表结构的,即行和列,填充二维数组不能通过简单的添加到数组操作来完成。 本篇文章介绍如何在 Java 中填充二维数组。
计算 Java 数组中的重复元素
发布时间:2023/05/01 浏览次数:202 分类:Java
-
本篇文章介绍Java计算数组中重复元素的方法。计算 Java 数组中的重复元素。我们可以创建一个程序来计算数组中的重复元素。 该数组可以是未排序的,也可以是已排序的。
Java 中 List 和 Arraylist 的区别
发布时间:2023/05/01 浏览次数:90 分类:Java
-
表示为单个单元的一组单个对象称为集合。 在 Java 中,Collection 是一个具有多个已定义接口和类的框架,用于将一组对象表示为一个单元。 它允许我们操纵