以下是JMM的三个“事先发生”规则。我没有列出其他规则,因为我的问题只与这三条规则有关。
问题
第一条规则问题 - 假设两个线程A和B都有同步的代码块。第一个规则是否意味着在线程A的同步块中设置的任何变量对于线程B的同步块中的代码是可见的,即使该变量未被声明为volatile?
第二条规则问题 - 假设线程A启动一个线程B.第二条规则是否意味着在调用start()之前在父线程中设置的任何变量都将对线程可见B即使变量未声明为volatile?
第3条规则问题 - 让我们说线程A中断线程B.第三条规则是否意味着在中断线程B之前在线程A中设置的任何变量都将在线程B后可见即使变量未声明为volatile,也会检测到中断?
最后,还有一个问题:
内存一致性效果:与其他并发集合一样,在将对象放入BlockingQueue之前的>线程中的操作发生在操作之前>在从另一个线程中的BlockingQueue访问或删除该元素之后
这是否意味着在将对象从队列中出列后,在阻塞队列中对象排队之前,线程A中设置的任何变量都是可见的,即使该变量未被声明为volatile?
基本上通过上述问题,我试图了解在这些事件之后是否发生内存刷新,以便在这些情况下不需要将变量声明为volatile。
答案 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条规则问题......
是的。
- ...... BlockingQueue ......
醇>
是的。
......通过上述问题,我试图了解内存刷新是否发生在这些事件之后......
不要考虑"记忆冲洗"。这不是Java语言的一部分:如果它发生了,它是一个实现细节,除非你实现 JVM,否则你不必担心它。
您需要担心的唯一概念是"发生在"。
之前每当JLS说A 发生在 B之前时,就意味着如果A发生在线程1中,而B发生在线程2中,你可以证明那个A实际上确实在B之前实时发生,然后在A发生之前由线程1更新的任何字段将在B发生后保证在线程2中可见。