1

以下只是 JMM 的三个“先发生”规则。我没有列出其他规则,因为我的问题仅与这三个规则有关。

  • 监控锁定规则。监视器锁上的解锁发生在同一监视器锁上的每个后续锁之前。
  • 线程开始规则。对线程的 Thread.start 调用发生在已启动线程中的每个操作之前。
  • 中断规则。一个线程在另一个线程上调用中断发生在被中断的线程检测到中断之前(通过抛出 InterruptedException,或者调用 isInterrupted 或中断)。

问题

  1. 第一个规则问题- 假设两个线程 A 和 B 有同步的代码块。第一条规则是否意味着在线程 A 的同步块中设置的任何变量对线程 B 的同步块中的代码都是可见的,即使该变量未声明为易失性?

  2. 第二条规则问题- 假设线程 A 启动线程 B。第二条规则是否意味着在调用 start() 之前在父线程中设置的任何变量对线程 B 都是可见的,即使该变量未声明为 volatile ?

  3. 第三条规则问题- 假设线程 A 中断线程 B。第三条规则是否意味着线程 A 在中断线程 B 之前设置的任何变量在检测到中断后对线程 B 可见,即使该变量未声明为易挥发的?

最后,还有一个问题:

  1. 在 BlockingQueue 文档中,据说,

    内存一致性效果:与其他并发集合一样,>线程中的操作在将对象放入 BlockingQueue 之前发生在操作>在>另一个线程中从 BlockingQueue 中访问或删除该元素之后。

这是否意味着在将对象从队列中出列后,线程 A 中设置的任何变量在将对象入队之前对线程 B 可见,即使该变量未声明为易失性?

基本上通过上述问题,我试图了解内存刷新是否发生在这些事件之后,以便在这些情况下不需要将变量声明为易失性。

4

1 回答 1

1

第一个规则问题 - 假设两个线程 A 和 B 有同步的代码块。

线程没有代码。线程执行代码。

第一条规则是否意味着在线程 A 的同步块中设置的任何变量对线程 B 的同步块中的代码都是可见的,即使该变量未声明为易失性?

是的,假设我们有:

private int i;
private final Object lock = new Object();

void foobar(...) {
    ...
    synchronized(lock) {
        i = ...;
    }
}

int getI() {
    synchronized(lock) {
        return i;
    }
}

如果线程 A 调用foobar(),然后线程 B 随后调用getI(),则线程 B 将获得 的新值i

但请注意!我上面的示例不包括任何方法让您证明哪个呼叫实际上首先发生。如果您的程序依赖于以特定顺序发生的那些调用,那么它需要的不仅仅是互斥锁:它需要一些方法来使线程 Bwait()为线程 A 执行更新。


第二条规则问题 - 假设线程 A 启动线程 B。第二条规则是否意味着在调用 start() 之前在父线程中设置的任何变量对线程 B 都是可见的,即使该变量未声明为 volatile ?

是的,就是这个意思。

第三条规则问题...

是的。

  1. ...阻塞队列...

是的。


...通过上述问题,我试图了解内存刷新是否发生在这些事件之后......

甚至不要考虑“内存刷新”。这不是 Java 语言的一部分:如果它发生,它是一个实现细节,除非您正在实现JVM ,否则您无需担心它。

您需要担心的唯一概念是“发生在之前”。

每当 JLS 说 A发生在B 之前,这意味着如果 A 发生在线程 1 中,而 B 发生在线程 2 中,并且您可以实时证明A 确实确实发生在 B 之前,那么任何被更新的字段A 发生之前的线程 1 将保证在 B 发生之后的线程 2 中可见。

于 2015-09-01T13:58:35.007 回答