Volatile 解决线程可见性的问题

有如下一段程序代码:

public class Demo {
    private static boolean stop = false;
    public static void main(String[] args) throws InterruptedException {
        Thread thread = new Thread(()->{
            int i=0;
            while(!stop){
                i++;
            }
            System.out.println("the thread is stopped.i="+i);
        });

        thread.start();
        Thread.sleep(1000);
        stop = true;
    }
}

在这里插入图片描述
执行后,没有任何输出。线程却不停止。
说明while循环仍在执行,那么stop的值仍为false,说明stop=true 对while并没有生效。
这就是多线程的可见性问题
就是我们在外层将值改变,子线程没有看到变化。
如果要解决它,可以使用volatile关键字。

public class Demo {
    private volatile static boolean stop = false;
    public static void main(String[] args) throws InterruptedException {
        Thread thread = new Thread(()->{
            int i=0;
            while(!stop){
                i++;
            }
            System.out.println("the thread is stopped.i="+i);
        });

        thread.start();
        Thread.sleep(1000);
        stop = true;
    }
}

这次的结果为:
在这里插入图片描述
除了使用volatile关键字外,
如果在循环体while 中加入 Thread.sleep(0); 或者 System.out.println("the i="+i); 也可以停止线程。

为什么 Thread.sleep可以停止线程?
Thread.sleep(0) 可以停止线程的原因是:
这是因为在hotspot的server端虚拟机中,做了深度优化(client版本就没有这个问题)。

C:\Users\86137>java -version
java version "1.8.0_361"
Java(TM) SE Runtime Environment (build 1.8.0_361-b09)
Java HotSpot(TM) 64-Bit Server VM (build 25.361-b09, mixed mode)

JIT 做了如下的优化:

	while(!stop){
	    i++;
	    try {
	        Thread.sleep(1000);
	    } catch (InterruptedException e) {
	        e.printStackTrace();
	    }
	}
	//-->
	if(!stop){
		while(true){
			i++;
		}
	}

volatile可以禁止JIT的优化过程。

除了volatile,我们可以通过VM参数来设置JIT禁止优化:
首先我们把代码中private tatic boolean stop = false; 中的volatile去掉;
然后在执行的VM参数中配置-Djava.compiler=NONE 就会发现 while中的stop生效了,线程会停下来。
在这里插入图片描述

为什么print可以导致循环结束?
print中包括两个步骤,1.IO操作;2.Synchronized。
Synchronized的释放,会将工作内存中的操作同步到主内存。所以stop最新的值会被while(!stop)读取到。
我们可以从如下示例中看到这个现象:

	while(!stop){
	    i++;
	    synchronized (Demo.class){
	        
	    }
	}

加了一个Synchronized的锁,会发现线程开启执行后,会停下来。

而IO操作会涉及到与内存、硬盘的交互,它会阻塞线程。 比如:

   while(!stop){
        i++;
        new File("test.java");
    }

加了IO操作,也会使线程停下来。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值