发生前和易变变量

时间:2015-09-01 10:57:47

标签: java multithreading concurrency happens-before

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

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

问题

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

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

  3. 第3条规则问题 - 让我们说线程A中断线程B.第三条规则是否意味着在中断线程B之前在线程A中设置的任何变量都将在线程B后可见即使变量未声明为volatile,也会检测到中断?

  4. 最后,还有一个问题:

    1. 在BlockingQueue文档中,据说,
        

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

    2. 这是否意味着在将对象从队列中出列后,在阻塞队列中对象排队之前,线程A中设置的任何变量都是可见的,即使该变量未被声明为volatile?

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

1 个答案:

答案 0 :(得分:1)

  

第一条规则问题 - 让我们说两个线程A和B都有同步的代码块。

主题没有拥有代码。线程执行代码。

  

第一个规则是否意味着线程A中同步块中设置的任何变量对于线程B的同步块中的代码是可见的,即使该变量未被声明为volatile?

是的,假设我们有:

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

但请注意!我上面的例子中没有任何方法可以证明哪个呼叫实际上是先发生的。如果你的程序依赖于那些按特定顺序发生的调用,那么它需要的不仅仅是一个互斥体:它需要一些方法来为线程制作线程B wait() A执行更新。

  

第二条规则问题 - 让我们说一个线程A启动一个线程B.第二条规则是否意味着在调用start()之前在父线程中设置的任何变量都将对线程B可见,即使该变量是没有声明为volatile?

是的,这意味着什么。

  

第3条规则问题......

是的。

  
      
  1. ...... BlockingQueue ......
  2.   

是的。

  

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

不要考虑"记忆冲洗"。这不是Java语言的一部分:如果它发生了,它是一个实现细节,除非你实现 JVM,否则你不必担心它。

您需要担心的唯一概念是"发生在"。

之前

每当JLS说A 发生在 B之前时,就意味着如果A发生在线程1中,而B发生在线程2中,你可以证明那个A实际上确实在B之前实时发生,然后在A发生之前由线程1更新的任何字段将在B发生后保证在线程2中可见。