演示volatile变量代码的坑
先直接上代码。演示没达到效果,本来希望非volatile变量要造成死循环,而volatile变量能及时感知共享变量的变化。而结果是非volatile虽然有延时,居然也能感知共享变量的变化而中断了死循环。原来此处主要是println语句的坑。println语句有锁,能自动更新共享变量的值。注释掉这样的打印语句就对了。idea的环境安装的时候自己就是server模式。排除了client模式启动的嫌疑。
package com.liux.lxtest.thread;
import lombok.extern.slf4j.Slf4j;
/**
* @ClassName Test1
* @Description xxx
* @Author LiuXiao
* @Date 2020.03.23 17:42
* @Version 1.0
**/
@Slf4j
public class Test1 {
public static void main(String[] args) {
VolatileThread volatileThread = new VolatileThread();
volatileThread.start();
try {
//设为1-3毫秒不起作用,会立即退出。设为4毫秒以上,非volatile变量才会有死循环出现。
Thread.sleep(4);
} catch (InterruptedException e) {
e.printStackTrace();
}
volatileThread.setContinue(false);
// System.out.println内部使用了synchronized关键字,
// 会使循环的线程读取到isContinue标识的修改,使得产生了一种非volatile变量似乎也有volatile的立见性的错觉。
//System.out.println(volatileThread.getContinue());
log.info(volatileThread.getContinue()+"");
}
}
@Slf4j
class VolatileThread extends Thread{
private int i =0;
private boolean isContinue = true;
//private volatile boolean isContinue = true;
public void setContinue(boolean aContinue) {
isContinue = aContinue;
}
public boolean getContinue(){
return this.isContinue;
}
@Override
public void run() {
System.out.println("begin......");
while (isContinue){
// 循环体内有语句,非volatile变量起不到演示死循环的效果。
// 因为println语句有同步锁,使得标识的改变,即使对于非volatile变量也能及时感知。
// System.out.println("Continue..." + i++);
// log.info("continue...."+ i++);
// i++; //打断点查看i的变化情况,是不可能的。直接就觉查到了isContinue的改变,程序结束。
}
System.out.println("end!!!!!");
}
}
看java并发编程,涉及有关volatile的概念。看了网上很多文章,把代码拿来实践一把,发现运行结果跟预想的完全不一样。后来找来一个讲师的视频,发现他的示例里面写的是空体死循环。而我写的死循环里面有一个打印语句,方便我查看运行效果。不明白为啥会这样。再后来,看到一篇博客的回复里面有一个大神说,println语句是加了锁的,会主动更新循环标识符的值。使得线程工作内存的缓存变量要去同步主内存中的共享变量。这才恍然大悟。然后,还有其它一些小点,在程序里面作了注释。以免多久不看以后又忘了。留此记录。
有关java多线程共享变量的概念解释描述,可参见如下网友写的博客:
https://www.cnblogs.com/soaringEveryday/p/4418604.html