首页 新闻 搜索 专区 学院

volatile 可见性的证明,产生了问题

0
[待解决问题]

先上两段代码,
代码一

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的可见性。

这是为什么???我在朋友的提示下,开始以为是共享变量的问题,于是开始研究什么是共享变量,但是现在看来,问题并不是出在共享变量上。当然共享变量也要继续研究明白。

请大牛帮忙理解理解。

lukely的主页 lukely | 初学一级 | 园豆:147
提问于:2020-02-06 18:39

同问啊!!

小L要努力吖 3年前

@小L要努力吖: 后来明白了,大概原因是 打印语句属于主线程的任务(即main线程),如果中间加了一个线程,相当于一个线程里面加入了另外一个线程,加入的时候,原来的线程时间被主线程接管了,这就是失败的原因,如果换成别的代码,比如随便在while循环里面做自增运算,就不会存在这个问题。所以这里估计又涉及到了线程嵌套的问题。应该差不多就是这样。还是想等看看有没有大神可以帮忙看看。

lukely 3年前

@lukely: 我昨天研究了下这个问题,发现主要原因在于执行System.out.println();这句话时,会有一个上锁的过程,然后使用了synchronized上锁这个操作后会做以下操作:

  1.获得同步锁

  2.清空工作内存

  3.从主内存中拷贝对象副本到本地内存

  4.执行代码(打印语句或加加操作)

  5.刷新主内存数据

  6.释放同步锁
具体你可以看下我写的这篇博客:https://www.cnblogs.com/ljl150/p/12484877.html

小L要努力吖 3年前
< >
分享
清除回答草稿
   您需要登录以后才能回答,未注册用户请先注册