简体   繁体   English

发生前和可变变量

[英]Happens-before and volatile variable

Following are just three "happens-before" rules of JMM. 以下只是JMM的三个“先发生”规则。 I am not listing the other rules as my question is related to these three rules only. 我没有列出其他规则,因为我的问题仅与这三个规则有关。

  • Monitor lock rule. 监视锁定规则。 An unlock on a monitor lock happens before every subsequent lock on that same monitor lock. 监视器锁的解锁发生在该监视器锁上的每个后续锁之前。
  • Thread start rule. 线程启动规则。 A call to Thread.start on a thread happens before every action in the started thread. 在启动线程中的每个操作之前,都会在线程上调用Thread.start。
  • Interruption rule. 中断规则。 A thread calling interrupt on another thread happens before the interrupted thread detects the interrupt (either by having InterruptedException thrown, or invoking isInterrupted or interrupted). 一个线程在另一个线程上调用中断发生在被中断的线程检测到中断之前(通过引发InterruptedException或调用isInterrupted或被中断)。

Questions 问题

  1. 1st rule question - Let's say two threads A and B have synchronized blocks of code. 第一个规则问题 -假设两个线程A和B具有同步的代码块。 Does the first rule mean that any variable set in a synchronized block in thread A, will be visible to the code in synchronized block of thread B, even if the variable is NOT declared as volatile? 第一条规则是否意味着即使未将变量声明为volatile,线程A的同步块中设置的任何变量对于线程B的同步块中的代码也将可见?

  2. 2nd rule question - Let's say a thread A starts a thread B. Does the second rule mean that any variable set in a parent thread before calling start() will be visible to thread B even if the variable is NOT declared as volatile? 第二条规则问题 -假设一个线程A启动了一个线程B。第二条规则是否意味着即使在该变量未声明为volatile的情况下,调用start()之前在父线程中设置的任何变量对线程B也是可见的?

  3. 3rd rule question - Let's say a thread A interrupts a thread B. Does the third rule mean that any variable set in thread A before interrupting thread B will be visible to thread B after the interrupt is detected, even if the variable is not declared as volatile? 第三条规则问题 -假设一个线程A中断了一个线程B。第三条规则是否意味着在检测到中断后,线程A在线程A之前设置的任何变量在线程B之前对线程B都是可见的,即使该变量未声明为挥发性?

Finally, one more question: 最后,还有一个问题:

  1. In BlockingQueue documentation, it is said, 在BlockingQueue文档中说,

    Memory consistency effects: As with other concurrent collections, actions in a >thread prior to placing an object into a BlockingQueue happen-before actions >subsequent to the access or removal of that element from the BlockingQueue in >another thread. 内存一致性影响:与其他并发集合一样,在将对象放入BlockingQueue之前,在>线程中执行的操作要先于在另一个线程中的BlockingQueue中访问或删除该元素之后的操作。

Does this mean any variable set in a thread A before enqueuing an object in the blocking queue will be visible to thread B after dequeuing the object from the queue, even if the variable is NOT declared as volatile? 这是否意味着在将对象从队列中出队后,线程A中在将对象放入队列中之前在线程A中设置的任何变量对于线程B都是可见的,即使该变量未声明为volatile也不行?

Basically through the above questions, I am trying to understand if the memory flush happens after these events such that the variables need not be declared as volatile in these cases. 基本上通过上面的问题,我试图了解在这些事件之后是否发生了内存刷新,从而在这些情况下不需要将变量声明为volatile。

1st rule question - Let's say two threads A and B have synchronized blocks of code. 第一个规则问题-假设两个线程A和B具有同步的代码块。

Threads don't have code. 线程不必代码。 Threads execute code. 线程执行代码。

Does the first rule mean that any variable set in a synchronized block in thread A, will be visible to the code in synchronized block of thread B, even if the variable is NOT declared as volatile? 第一条规则是否意味着即使未将变量声明为volatile,线程A的同步块中设置的任何变量对于线程B的同步块中的代码也将可见?

Yes, Suppose we have: 是的,假设我们有:

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

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

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

If thread A calls foobar() , and then thread B subsequently calls getI() , then thread B will get the new value of i . 如果线程A调用foobar() ,然后线程B随后调用getI() ,则线程B将获得i的新值。

But note! 但是请注意! My example above does not include any way for you to prove which call actually happened first. 我上面的示例没有提供任何方法来证明哪个呼叫最先发生。 If your program depends on those calls to happen in a particular order, then it's going to need more than just a mutex: It's going to need some means to make thread B wait() for thread A to perform the update. 如果您的程序依赖于以特定顺序发生的那些调用,那么它不仅需要互斥锁:它还需要一些方法来使线程B wait()使线程A执行更新。


2nd rule question - Let's say a thread A starts a thread B. Does the second rule mean that any variable set in a parent thread before calling start() will be visible to thread B even if the variable is NOT declared as volatile? 第二条规则问题-假设一个线程A启动了一个线程B。第二条规则是否意味着即使在该变量未声明为volatile的情况下,调用start()之前在父线程中设置的任何变量对线程B也是可见的?

Yes, that's what it means. 是的,就是这个意思。

3rd rule question... 第三条规则问题...

Yes again. 再来一次

  1. ... BlockingQueue ... ... BlockingQueue ...

Yes again. 再来一次


...Through the above questions, I am trying to understand if the memory flush happens after these events such that... 通过上述问题,我试图了解在这些事件之后是否发生了内存刷新,从而...

Don't even think about "memory flush". 甚至不要考虑“内存刷新”。 That is not part of the Java language: If it happens, it's an implementation detail, and you don't need to worry about it unless you are implementing a JVM. 那不是Java语言的一部分:如果发生这种情况,那是实现细节,除非您正在实现 JVM,否则不必担心。

The only concept you need to worry about is the "happens before". 您唯一需要担心的概念是“发生之前”。

Whenever the JLS says that A happens before B, it means that if A happens in thread 1, and B happens in thread 2, and you can prove that A actually did happen before B in real-time, then any field that was updated by thread 1 before A happened will be guaranteed visible in thread 2 after B happens. 只要JLS说A 发生在 B 之前 ,就意味着如果A发生在线程1中,而B发生在线程2中,并且您可以实时证明 A确实确实发生在B之前,那么任何由保证A发生之前的线程1在B发生之后在线程2中可见。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM