Java op的身体。在这个粗锁之外唯一要做的事情就是创建第一个字符串值,它是您观察到的旧值
有关JMM的更多信息,请参阅。另外,请查看最终决定可见性的变量。如果只查看volatile变量的读取和写入,则它们必须按以下顺序显示:Java op的身体。在这个粗锁之外唯一要做的事情就是创建第一个字符串值,它是您观察到的旧值,java,multithreading,java.util.concurrent,java-memory-model,Java,Multithreading,Java.util.concurrent,Java Memory Model,有关JMM的更多信息,请参阅。另外,请查看最终决定可见性的变量。如果只查看volatile变量的读取和写入,则它们必须按以下顺序显示: 1 - main: read run (run is true) 2 - Thread-0: write run (run is false) 3 - main: read run (run is false) 但是控制台输出是独立的操作,不需要在读取之后立即执行。println参数的计算和方法调用不是原子的。所以我们有一些更像: 1 - main: read
1 - main: read run (run is true)
2 - Thread-0: write run (run is false)
3 - main: read run (run is false)
但是控制台输出是独立的操作,不需要在读取之后立即执行。println参数的计算和方法调用不是原子的。所以我们有一些更像:
1 - main: read run (run is true)
2 - main: println("Run: true")
3 - Thread-0: write run (run is false)
4 - Thread-0: println("Run: false")
5 - main: read run (run is false)
6 - main: println("Run: false")
这允许在第一次排序之后进行排序,如:
1 - main: read run (run is true)
3 - Thread-0: write run (run is false)
4 - Thread-0: println("Run: false")
2 - main: println("Run: true")
5 - main: read run (run is false)
6 - main: println("Run: false")
根据中的源代码,行:
System.out.println(Thread.currentThread().getName() + " run:" + run);
可以内联如下:
String x = Thread.currentThread().getName() + " run:" + run;
synchronized(System.out.lock) {
System.out.print(x);
System.out.println();
}
因此,println
中存在同步,但不包括读取run
。这意味着run
的值可以在读取和输出之间更改,从而导致run
的旧值被输出
为了获得预期的输出,同步块需要同时包含
run
和println
语句的设置。另一个线程上的run
和println
语句的读取需要位于同一锁上的另一个同步块中。如果只查看volatile变量的读取和写入,则它们必须按以下顺序出现:
1 - main: read run (run is true)
2 - Thread-0: write run (run is false)
3 - main: read run (run is false)
但是控制台输出是独立的操作,不需要在读取之后立即执行。println参数的计算和方法调用不是原子的。所以我们有一些更像:
1 - main: read run (run is true)
2 - main: println("Run: true")
3 - Thread-0: write run (run is false)
4 - Thread-0: println("Run: false")
5 - main: read run (run is false)
6 - main: println("Run: false")
这允许在第一次排序之后进行排序,如:
1 - main: read run (run is true)
3 - Thread-0: write run (run is false)
4 - Thread-0: println("Run: false")
2 - main: println("Run: true")
5 - main: read run (run is false)
6 - main: println("Run: false")
根据中的源代码,行:
System.out.println(Thread.currentThread().getName() + " run:" + run);
可以内联如下:
String x = Thread.currentThread().getName() + " run:" + run;
synchronized(System.out.lock) {
System.out.print(x);
System.out.println();
}
因此,println
中存在同步,但不包括读取run
。这意味着run
的值可以在读取和输出之间更改,从而导致run
的旧值被输出
为了获得预期的输出,同步块需要同时包含
run
和println
语句的设置。另一个线程上的run
和println
语句的读取需要位于同一锁上的另一个同步块中。请创建一个mvce。想要运行您发布的代码的人不必从不完整的代码片段中重建它。@NathanHughes:什么是mvce?在这个场景中还有另一个共享资源:System.out
.mvce=最小值代码示例。@MikeSamuel:您介意解释一下吗?请制作一个mvce。想要运行您发布的代码的人不必从不完整的代码片段中重建它。@NathanHughes:什么是mvce?在这个场景中还有另一个共享资源:System.out
.mvce=最小值代码示例。@MikeSamuel:您介意解释一下吗?嗯,我希望正确的行为类似于main*run:true main*run:true main*run:true main*run:true main*run:true Thread-0将run设置为false main*run:true main*run:true main*run:true Thread-0 run:false main**run:false退出代码>这有时会发生。那么,为什么会出现上述偏差呢?你能用预期的行为编辑帖子吗。很难在评论中读到谢谢是的,我理解你描述的流程。然而,让我困惑的是,即使run
被指定为volatile,main
线程在Tread-0
中更新时(参见第一个片段),在第二个片段中更新时(根据System.out.println)也不会得到更新的值似乎完全不正常:main
甚至在Thread-0
中更新run
之前就退出了。我在帖子的文本中添加了预期的行为。谢谢,我不太明白。您放入的时间戳似乎在重新排序主线程中的程序顺序
——这是否违反了根据Java内存模型规范定义为volatile
的运行
的合同,我希望正确的行为类似于main*run:true main*run:true main*run:true main*run:true main*run:true Thread-0将run设置为false main*run:true main*run:true main*run:true Thread-0 run:false main**run:false退出代码>这有时会发生。那么,为什么会出现上述偏差呢?你能用预期的行为编辑帖子吗。很难在评论中读到谢谢是的,我理解你描述的流程。然而,让我困惑的是,即使run
被指定为volatile,main
线程在Tread-0
中更新时(参见第一个片段),在第二个片段中更新时(根据System.out.println)也不会得到更新的值似乎完全不正常:main
甚至在Thread-0
中更新run
之前就退出了。我在帖子的文本中添加了预期的行为。谢谢,我不太明白。您输入的时间戳似乎在重新排序主线程中的程序顺序
-这是否违反了根据Java内存模型规范定义为易失性
的运行
的合同?Rafael,我昨天听了您的演讲,这就是为什么,激励我深入理解这个输出的行为。我还是很困惑。您说:“当A想要打印到控制台时,它需要为System.out重新请求监视器,这会导致刷新缓冲区,以便B中的后续消息打印更新的消息。”但是,此顺序与此前提相矛盾:Thread-0 run:false
main*run:true
main**run:false
。
// run = false; //becomes ========
synchronized(someLock) {
run = flase;
}
// =======================
//System.out.println(run); //becomes =========
synchronized(someLock) {
boolean tmpBoolean = run;
}
System.out.println(tmpBoolean);
//=================
System.out.println(Thread.currentThread().getName() + "* run: " + run);
String text = Thread.currentThread().getName() + "* run: " + run;
System.out.println(text);
/*A*/ String text = Thread.currentThread().getName() + "* run: " + run;
/*B*/ System.out.println(Thread.currentThread().getName() + " setting run to false");
/*B*/ run = false;
/*B*/ System.out.println(Thread.currentThread().getName() + " run:" + run);
/*A*/ System.out.println(text);
/*A*/ if(run == false) {
/*A*/ System.out.println(Thread.currentThread().getName() + "** run: " + run + "\nExiting...");
/*A*/ System.exit(0);
/*A*/ }
1 - main: read run (run is true)
2 - Thread-0: write run (run is false)
3 - main: read run (run is false)
1 - main: read run (run is true)
2 - main: println("Run: true")
3 - Thread-0: write run (run is false)
4 - Thread-0: println("Run: false")
5 - main: read run (run is false)
6 - main: println("Run: false")
1 - main: read run (run is true)
3 - Thread-0: write run (run is false)
4 - Thread-0: println("Run: false")
2 - main: println("Run: true")
5 - main: read run (run is false)
6 - main: println("Run: false")
System.out.println(Thread.currentThread().getName() + " run:" + run);
String x = Thread.currentThread().getName() + " run:" + run;
synchronized(System.out.lock) {
System.out.print(x);
System.out.println();
}