public class MyselfTest {
public static boolean flag = false;
public static void main(String[] args) throws InterruptedException {
Thread thread = new Thread(() ->{
int i = 0;
while (!flag) {
i++;
}
System.out.println("i = " + i);
});
thread.start();
Thread.sleep(1000);
flag = true;
}
}
该代码按照逻辑来说,flag变为true之后是会打印出结果的,但代码并未退出且打印出结果,这是一个可见性问题。那有哪些方法可以让线程退出呢?
int i = 0;
while (!flag) {
i++;
System.out.println("i = " + i);
}
这里有三个解释:
- println底层用了synchronized这个同步关键字,这个同步会防止循环期间对于stop值的缓存
- 因为println有加锁操作,而释放锁的操作,会强制的把工作内存中涉及到的写操作同步到主内存,可以通过如下代码去证明:
while (!flag) {
i++;
synchronized (MyselfTest.class) {
}
}
上述代码只是加锁了并未做任何操作也能达到同样的效果
3. 从IO角度来说,println本质上就是IO操作,我们知道IO的效率一定要比CPU的计算效率慢的多,所以IO可以使得CPU有时间去做内存刷新的事情,从而导致这个现象。比如在里面定义一个new File("")同样会达到效果
while (!flag) {
i++;
try {
Thread.sleep(0);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
Thread.sleep(0)会导致线程切换,从而导致缓存失效获取到最新的数值
- 修改volatile变量时会强制将修改后的值刷新的主内存中。
- 修改volatile变量后会导致其他线程工作内存中对应的变量值失效。因此,再读取该变量值的时候就需要重新从读取主内存中的值。