首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >等待()并通知() JMM语义

等待()并通知() JMM语义
EN

Stack Overflow用户
提问于 2020-05-02 16:15:29
回答 1查看 74关注 0票数 1

我有一个很特别的问题,我找不到答案。

正如我们所知道的,在synchronized块中的入口,一个线程对其作用域中的所有共享(非本地)变量执行重读。某些底层体系结构的示例:如果线程A更新RAM中对象的状态,则进入同步块的线程B将看到更改。在退出synchronized块时也会发生类似的事情:线程将其作用域中的所有内容都刷新到内存中,以便其他线程可以看到它。这些都是JVM可见性的基本保证,也是在出现强制执行规则之前发生的情况。

但是,在语义上,使用wait()notify()的代码是否也做了所有这一切并不十分清楚:毕竟,它没有明确地输入或离开synchronized块。

问题如下:

JVM是否确保对notify()入口上其他线程的更改的可见性? JVM是否确保在上其他线程中所做的更改的可见性?

  1. 是否确保了对wait()上其他线程的更改的可见性?
EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2020-05-02 16:32:58

正如我们所知,在同步块的入口,线程对其作用域中的所有变量进行重新读取;也就是说,如果线程A更新RAM中的对象的状态,进入同步块的线程B将看到更改。

第一部分是不正确的。并不是所有的变量都是重读的。局部变量是不确定的。它们不需要重读,因为它们在另一个线程中是不可见的。

正确的语句是编译器将确保线程A在退出该块之前编写的共享变量在B进入该块后对线程B可见。条件是A和B在同一个互斥对象上同步,并且同时A(或其他一些线程)没有覆盖它们。

没有与notifynotifyAll关联的显式内存语义。然而,wait将导致互斥体被释放并(通常)重新获得.在与其他线程建立关系之前,发布和重新获取就已经发生了。

,请您详细说明与释放和获取锁有关的确切语义吗?它们是否与输入同步块相同?

让我们假设我们只有两个线程,A和B,以及一个互斥线程。

还请记住,只有持有锁的线程才能调用waitnotify

  1. 线程A获得L.
  2. Thread A calls L.wait().
    • 线程A被放置在L的等待队列中,L被释放。

  1. 线程B获取L.
  2. 线程B调用L.notify()
    • 线程A被移动到等待获取
    • 的线程队列上

  1. 线程B发布L.
  2. 线程A-重新获取锁,L.wait()调用返回。

在这里重要的边缘之前发生的是介于2到3之间,然后是5到6之间。

如果涉及多个线程,则可以通过在关系之前链接发生的情况来分析行为。但是在释放互斥锁的线程和下一个线程之间只有一个直接HB来获取它.无论如何都行。

所以,你的问题的答案是:

( 1) & 2)是的,假设另一个线程正确地使用了synchronized。( 3)不。可见点是当互斥对象由名为notify()的线程释放时。

请注意,内存屏障、刷新等是实现细节。事实上,编译器可以自由地实现发生的语义--在它想要的任何方式之前。包括(假设)优化清除内存刷新,如果它们是不必要的。

最好(海事组织)忽略这些实施细节,只考虑发生-之前的关系。

有关发生之前发生的更多信息,请阅读:

票数 6
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/61562542

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档