我有以下代码:
private volatile boolean run = true;
private Object lock =new Object();
…………
Thread newThread = new Thread(new Runnable() {
@Override
public void run() {
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
synchronized (lock) {
System.out.println(Thread.currentThread().getName()
+ " run:" + run);
System.out.println(Thread.currentThread().getName()
+ " setting run to false");
run = false;
System.out.println(Thread.currentThread().getName()
+ " run:" + run);
}
}});
newThread.start();
while(true) {//no synchronization, so no coordination guarantee
System.out.println(Thread.currentThread().getName() + "* run: "+run);
if(run == false) {
System.out.println(Thread.currentThread().getName() + "** run: "+run+"\nExiting...");
System.exit(0);
}
}
which generates the following output:
main* run: true
main* run: true
main* run: true
main* run: true
main* run: true
main* run: true
main* run: true
main* run: true
main* run: true
main* run: true
main* run: true
main* run: true
main* run: true
main* run: true
Thread-0 setting run to false
Thread-0 run:false
main* run: true <- what causes this???
main** run: false
Exiting...
我试图理解为什么在主线程中发生 main* run: true 的异常,考虑到 run
是一个易变的字段并且根据 Java 内存模型规范中,Thread-0
中的 volatile 写入应该立即被 main
线程可见。我知道 Thread-0
中的同步在这里是无关紧要的,但我对 volatile 的这种行为感到困惑。我在这里错过了什么?
另一个更奇怪的运行产生了这个:
main* run: true
main* run: true
main* run: true
main* run: true
main* run: true
main* run: true
main* run: true
main* run: true
main* run: true
main* run: true
main* run: true
main* run: true
main* run: true
main* run: true
main* run: true
main* run: true
main* run: true
main* run: true
main* run: true
main* run: true
main* run: true
main* run: true
main** run: false
Exiting...
Thread-0 run:false
或者这种行为是可以预料的,如果是,为什么?谢谢。
编辑:正如评论中所问,我正在用我有时但并非总是看到的预期输出更新帖子:
main* run: true
main* run: true
main* run: true
main* run: true
main* run: true
main* run: true
main* run: true
main* run: true
main* run: true
main* run: true
main* run: true
Thread-0 setting run to false
main* run: true
main* run: true
main* run: true
Thread-0 run:false
main** run: false
Exiting...
换句话说,我不想看到:
main* run: true
出现在
之后Thread-0 run:false
或
main** run: false
Exiting...
出现在
之前Thread-0 run:false
最佳答案
我没有看到问题。这里的锁是没用的。 volatile 也意味着变量在自身内部是同步的。这里发生了什么。每当有多个线程时,每个线程都会自行运行而不关心其他线程。所以在这种情况下,我们有两个线程:main 和 thread-0。 Main 自行运行并到达打印变量 run
的位置,因此它会打印它。另一个线程 hibernate 了一点(这应该无关紧要,也不应该是让其他线程先工作的方式),然后将变量 run
更改为 false。主线程读取新值并存在
按照时间顺序你就明白了
Thread newThread = new Thread(new Runnable() {
@Override
public void run() {
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
synchronized (lock) {
System.out.println(Thread.currentThread().getName()
+ " run:" + run);
System.out.println(Thread.currentThread().getName()
+ " setting run to false");
run = false; //<---- time_4
System.out.println(Thread.currentThread().getName()
+ " run:" + run); //<---- time_5
}
}});
newThread.start();
while(true) { //<---- time_2
System.out.println(Thread.currentThread().getName() + "* run: "+run); //<--- time_3 getting the value of run variable. //<---- time_6 printing
if(run == false) { //<---- time_1 (run == true) // <---- 2nd iteration time_7 (run == false)
System.out.println(Thread.currentThread().getName() + "** run: "+run+"\nExiting..."); //<---- time_8
System.exit(0);
}
}
无论如何,这里是如何修复你的代码以获得预期的输出(注意:volatile 在这里没有做任何事情):
synchronized (lock) {
if(run == false) {
System.out.println(Thread.currentThread().getName() + "** run: "+run+"\nExiting...");
System.exit(0);
}
}
这就是 volatile 对变量 run
的基本作用:
// run = false; //becomes ========
synchronized(someLock) {
run = flase;
}
// =======================
//System.out.println(run); //becomes =========
synchronized(someLock) {
boolean tmpBoolean = run;
}
System.out.println(tmpBoolean);
//=================
关于java - Java volatile字段跨线程读写协调理解,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/39312933/