先上两段代码,
代码一
package com.luke.Thread;
public class VolatileDemo003 extends Thread {
private boolean isRun = true;
@Override
public void run() {
System.out.println("#######start########");
while (isRun) {
System.out.println("死循环了");
}
System.out.println("#######end########");
}
public void setRun(boolean isRun){
this.isRun = isRun;
}
public static void main(String[] args) throws InterruptedException {
VolatileDemo003 volatileDemo = new VolatileDemo003();
volatileDemo.start();
Thread.sleep(3000);
volatileDemo.setRun(false);
System.out.println("#######set to false########");
Thread.sleep(1000);
System.out.println(volatileDemo.isRun);
}
}
代码二:
package com.luke.Thread;
class DataNum{
int num = 0;
public void addNum() {
num = 60;
}
}
public class VolatileDemo002 {
public static void main(String[] args) {
seeByVolatile();
}
private static void seeByVolatile(){
DataNum dn = new DataNum();
new Thread(new Runnable() {
@Override
public void run() {
System.out.println("线程开始");
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
dn.num = 60;
System.out.println("线程修改结束" + dn.num);
}
}).start();
while(dn.num == 0){
//System.out.println("可见性测试失败");
}
System.out.println("主线程和分线程都执行结束了");
}
}
这两段代码都是用于证明volatile的可见性的。
现在发现,在变量不加volatile的的情况,如果while循环里面加上一句打印的语句,随便打印什么,就不会产生死循环。如果while循环里面什么都没有的话,就可以实现死循环,这样也就可以证明volatile的可见性。
这是为什么???我在朋友的提示下,开始以为是共享变量的问题,于是开始研究什么是共享变量,但是现在看来,问题并不是出在共享变量上。当然共享变量也要继续研究明白。
请大牛帮忙理解理解。
同问啊!!
– 小L要努力吖 4年前@小L要努力吖: 后来明白了,大概原因是 打印语句属于主线程的任务(即main线程),如果中间加了一个线程,相当于一个线程里面加入了另外一个线程,加入的时候,原来的线程时间被主线程接管了,这就是失败的原因,如果换成别的代码,比如随便在while循环里面做自增运算,就不会存在这个问题。所以这里估计又涉及到了线程嵌套的问题。应该差不多就是这样。还是想等看看有没有大神可以帮忙看看。
– lukely 4年前@lukely: 我昨天研究了下这个问题,发现主要原因在于执行System.out.println();这句话时,会有一个上锁的过程,然后使用了synchronized上锁这个操作后会做以下操作:
1.获得同步锁
2.清空工作内存
3.从主内存中拷贝对象副本到本地内存
4.执行代码(打印语句或加加操作)
5.刷新主内存数据
6.释放同步锁
– 小L要努力吖 4年前具体你可以看下我写的这篇博客:https://www.cnblogs.com/ljl150/p/12484877.html