happens-before 和 volatile 变量
Happens-before and volatile variable
以下是 JMM 的三个 "happens-before" 规则。我没有列出其他规则,因为我的问题仅与这三个规则有关。
- 监控锁定规则。监视器锁上的解锁发生在每个
同一监视器锁上的后续锁。
- 线程启动规则。在线程上调用 Thread.start 之前发生
启动线程中的每个操作。
- 中断规则。一个线程在另一个线程上调用中断
在被中断的线程检测到中断之前发生(或者
通过抛出 InterruptedException,或调用 isInterrupted 或
打断了)。
问题
第一个规则问题 - 假设两个线程 A 和 B 具有同步代码块。第一条规则是否意味着在线程 A 的同步块中设置的任何变量对线程 B 的同步块中的代码都是可见的,即使该变量未声明为 volatile?
第二条规则问题 - 假设线程 A 启动线程 B。第二条规则是否意味着在调用 start 之前在父线程中设置的任何变量() 将对线程 B 可见,即使变量未声明为 volatile?
第三条规则问题 - 假设线程 A 中断线程 B。第三条规则是否意味着在中断线程 B 之前在线程 A 中设置的任何变量将在检测到中断后对线程 B 可见,即使该变量未声明为 volatile?
最后还有一个问题:
- 在 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.
这是否意味着线程 A 在将对象入队之前在阻塞队列中设置的任何变量在将对象从队列中出队后对线程 B 可见,即使该变量未声明为 volatile?
基本上通过上述问题,我试图了解内存刷新是否发生在这些事件之后,以便在这些情况下不需要将变量声明为 volatile。
1st rule question - Let's say two threads A and B have synchronized blocks of 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?
是的,假设我们有:
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 执行更新。
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?
是的,就是这个意思。
3rd rule question...
又是。
- ... BlockingQueue ...
又是。
...Through the above questions, I am trying to understand if the memory flush happens after these events such that...
想都别想 "memory flush"。那不是 Java 语言的一部分:如果它发生了,那是一个实现细节,除非您正在 实现 JVM,否则您无需担心它。
您唯一需要担心的概念是 "happens before"。
每当JLS说A happens before B时,这意味着如果A发生在线程1中,B发生在线程2中,你可以证明 A 确实实时发生在 B 之前,那么在 A 发生之前由线程 1 更新的任何字段都将保证在 B 发生后在线程 2 中可见。
以下是 JMM 的三个 "happens-before" 规则。我没有列出其他规则,因为我的问题仅与这三个规则有关。
- 监控锁定规则。监视器锁上的解锁发生在每个 同一监视器锁上的后续锁。
- 线程启动规则。在线程上调用 Thread.start 之前发生 启动线程中的每个操作。
- 中断规则。一个线程在另一个线程上调用中断 在被中断的线程检测到中断之前发生(或者 通过抛出 InterruptedException,或调用 isInterrupted 或 打断了)。
问题
第一个规则问题 - 假设两个线程 A 和 B 具有同步代码块。第一条规则是否意味着在线程 A 的同步块中设置的任何变量对线程 B 的同步块中的代码都是可见的,即使该变量未声明为 volatile?
第二条规则问题 - 假设线程 A 启动线程 B。第二条规则是否意味着在调用 start 之前在父线程中设置的任何变量() 将对线程 B 可见,即使变量未声明为 volatile?
第三条规则问题 - 假设线程 A 中断线程 B。第三条规则是否意味着在中断线程 B 之前在线程 A 中设置的任何变量将在检测到中断后对线程 B 可见,即使该变量未声明为 volatile?
最后还有一个问题:
- 在 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.
这是否意味着线程 A 在将对象入队之前在阻塞队列中设置的任何变量在将对象从队列中出队后对线程 B 可见,即使该变量未声明为 volatile?
基本上通过上述问题,我试图了解内存刷新是否发生在这些事件之后,以便在这些情况下不需要将变量声明为 volatile。
1st rule question - Let's say two threads A and B have synchronized blocks of 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?
是的,假设我们有:
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 执行更新。
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?
是的,就是这个意思。
3rd rule question...
又是。
- ... BlockingQueue ...
又是。
...Through the above questions, I am trying to understand if the memory flush happens after these events such that...
想都别想 "memory flush"。那不是 Java 语言的一部分:如果它发生了,那是一个实现细节,除非您正在 实现 JVM,否则您无需担心它。
您唯一需要担心的概念是 "happens before"。
每当JLS说A happens before B时,这意味着如果A发生在线程1中,B发生在线程2中,你可以证明 A 确实实时发生在 B 之前,那么在 A 发生之前由线程 1 更新的任何字段都将保证在 B 发生后在线程 2 中可见。