当前位置: 首页 > 面试题库 >

Java为什么必须wait()始终处于同步块中

于鹏
2023-03-14
问题内容

我们都知道,为了调用Object.wait(),必须将此调用放置在同步块中,否则将IllegalMonitorStateException引发。但是,进行此限制的原因是什么?我知道这wait()释放了监视器,但是为什么我们需要通过使特定的块同步来显式获取监视器,然后通过调用来释放监视器wait()

如果可以wait()同步块之外调用并保留其语义-挂起调用者线程,可能造成什么损害?


问题答案:

wait()只有在还存在时,A才有意义notify(),因此它始终与线程之间的通信有关,并且需要同步才能正常工作。有人可能会争辩说这应该是隐式的,但这并没有真正的帮助,原因如下:

从语义上讲,你永远不会wait()。你需要满足一些条件,如果不是,请等到满足。所以你真正要做的是

if(!condition){
    wait();
}

但是条件是由单独的线程设置的,因此为了正确执行此工作,你需要同步。

还有其他一些问题,仅仅是因为线程退出等待并不意味着你要寻找的条件是正确的:

你可能会得到虚假的唤醒(这意味着线程可以从等待中唤醒而从未收到通知),或者

可以设置条件,但是第三个线程在等待线程唤醒(并重新获取监视器)时再次使条件变为假。

为了处理这些情况,你真正需要的始终是这种变化:

synchronized(lock){
    while(!condition){
        lock.wait();
    }
}

更好的是,根本不要弄乱同步原语,而要使用java.util.concurrent软件包中提供的抽象。



 类似资料:
  • Java中,任何对象都可以作为锁,并且 wait(),notify()等方法用于等待对象的锁或者唤醒线程,在 Java 的线程中并没有可供任何对象使用的锁,所以任意对象调用方法一定定义在Object类中。 wait(), notify()和 notifyAll()这些方法在同步代码块中调用 有的人会说,既然是线程放弃对象锁,那也可以把wait()定义在Thread类里面啊,新定义的线程继承于Thr

  • 问题内容: 即使等待1的linux手册页很好地说明了您需要让子进程不使其变成僵尸,但它根本无法说明原因。 我围绕一个Ever 循环计划了我的程序(这是我的第一个多线程程序,所以请原谅我的天真),该循环启动子进程,该子进程被ed淘汰,并确保自行终止。 我无法使用,因为这使并行计算变得不可能,因此我可能不得不添加一个存储子pid的进程表,并且不得不使用-不是立即执行,而是经过一段时间- 这是一个问题,

  • 问题内容: 我着手进行Java 8学习。 我发现了一个有趣的行为: 让我们看一下代码示例: 和模型类: 。对于顺序流,这个代码总是返回其是但对于平行,它总是返回其为(4等于流元素计数)。 当我看到此结果时,我以为并行流和顺序流返回不同的结果很奇怪。 我在某处违约了吗? 聚苯乙烯 对我来说,73是预期结果,但76不是。 问题答案: 标识值是这样的值。这是Java所独有的概念,例如,参见Wikiped

  • 问题内容: 为什么必须始终在Java中初始化局部变量(包括基元)?为什么相同的实例变量不适用? 问题答案: 基本上,要求在读取变量之前为其分配值是一件好事。这意味着您不会意外阅读您不想要的内容。是的,变量可以具有默认值-但如果编译器可以证明您正在尝试读取尚未分配的内容,那么编译器是否可以捕获错误不是更好吗?如果要为局部变量提供默认值,则始终可以显式分配。 现在,对于局部变量来说,这很好-但是对于实

  • //[input type=“text”placeholder=“First Name”class=“form control”ng model=“FirstName”必填项] 下面是我的代码 elemntvalue=驱动程序。FindElement(By.XPath(//input[@placeholder='First Name']); 字符串名称required=elemntvalue。Ge

  • 问题内容: 我已经开始学习线程同步。 同步方法: 同步块: 什么时候应该使用方法和块? 为什么块比方法更好? 问题答案: 这不是更好的问题,只是有所不同。 同步方法时,实际上是在与对象本身进行同步。对于静态方法,您正在同步到对象的类。因此,以下两段代码以相同的方式执行: 就像您写的一样。 如果要控制到特定对象的同步,或者只想将方法的 一部分 同步到该对象,则指定一个块。如果在方法声明上使用关键字,