我写这个程序来模拟field visibility
。
package com.example.threads.fieldvisibility.main;
public class ThreadVisibilityWithSyncKeyWord implements Runnable {
private boolean stop = false;
@Override
public void run() {
while (!stop) {
// System.out.println("stop is " + stop);
}
}
public static void main(String[] args) throws InterruptedException {
ThreadVisibilityWithSyncKeyWord test = new ThreadVisibilityWithSyncKeyWord();
Thread t = new Thread(test);
System.out.println("Starting Thread");
t.start();
Thread.sleep(5000);
System.out.println("Stopping Thread");
synchronized (test) {
test.stop = true;
}
t.join(5000);
System.out.println("Thread State: " + t.getState());
}
}
程序非常简单。我们有两个线程。主线程确实使用"test"对象在synchronized
块中将标志"stop"更改为true。
我希望一旦主线程将其设置为 true,它就会使 while 循环终止。 但是即使主线程将标志设置为 true,另一个线程也看不到最新值(即使它在同步块中更新(。
奇怪的是,当我取消注释System.out.println()
(在 while 内部(时,线程确实"看到"了最新值并终止。
我不理解这种行为。为什么另一个线程无法看到在主线程的同步块中更新的最新值。而在取消注释sysout
后,是什么导致另一个线程看到标志的最新值?
当线程进入synchronized
块时,通过从共享缓存/内存读取来保证看到访问变量的当前状态。在synchronized
块内写入变量将保证变量写入共享缓存/内存。
发生了什么:
- 创建
test
main
线程缓存test.stop
test
缓存false
stop
test
开始test
从本地缓存中读取stop
的值 (!main
线程集test.stop
true
- 由于这是同步完成的,因此写入也会完成对共享缓存的写入
test
不断从自己的缓存中读取stop
,该缓存仍然false
将打印行添加到代码时,必须知道System.out.println
涉及内部同步:
- 。
main
线程设置test.stop
true
- 由于这是同步完成的,因此写入也会完成对共享缓存的写入
test
执行println
,在那一刻,内部同步导致test
从共享缓存中读取新值
我认为主要问题是项目的结构,如果您将主线程类与可运行线程类分开,一切都会更容易。
这是具有以下结果的工作示例:(请注意,我在线程中添加了 1 秒睡眠以避免许多打印输出(
- 起始线程
- 停止为假
- 停止为假
- 停止为假
- 停止为假
- 停止线程
- 停止为真
-
线程状态:已终止
包共项目;
公共类 主 {
public static boolean stop = false; public static void main(String[] args) throws InterruptedException { ThreadVisibilityWithSyncKeyWord test = new ThreadVisibilityWithSyncKeyWord(); Thread t = new Thread(test); System.out.println("Starting Thread"); t.start(); Thread.sleep(5000); System.out.println("Stopping Thread"); stop = true; t.join(5000); System.out.println("Thread State: " + t.getState()); }
}
包共项目;
public class ThreadVisibilityWithSyncKeyWord implements Runnable {
@Override public void run() { while (!Main.stop) { try { Thread.sleep(1000); } catch (InterruptedException e) { } System.out.println("stop is " + Main.stop); } }
}