为什么我修改的数据没有启作用?
首先我们来看下下面的代码:
private static boolean isRun = true;
public static void sleep2s(){
try{
Thread thread = new Thread();
thread.sleep(2000);
}catch (Exception e){
System.out.println("出现异常");
}
}
public static void main(String[] args){
//另外启动一个线程计数
new Thread(new Runnable() {
@Override
public void run() {
//启动线程执行我的另外一个方法
Long i = 0L ;
while (TestMutiThread.isRun){
i++;
}
System.out.println("count值为:"+ i );
}
}).start();
//睡了2S
sleep2s();
TestMutiThread.isRun = false;
System.out.println("主线程执行结束");
}
我们执行这段代码之后会发现,如下图这种情况。
明明我已经将我的isRun的值设置为false,主程序程序还没有结束,说明还有另外的线程在执行操作?
其实是我们的while循环没有执行结束,那为什么while循环没有执行结束呢?无非就是isRun =true,但是我不是已经在输出程序运行结束之前,将它设置为false了,为什么没有完成呢?
想必你会有很多问题,我们娓娓道来!
说到这些问题,我们就不得不提到Java内存模型!
Java内存模型
我们之前在JVM虚拟机中说到,每个线程都有自己的线程栈。线程每次操作的时候都会优先操作自己的线程栈里面的数据,如果没有的话,去内存中取。
内存模型如下图:
从这里我们可以发现很多猫腻了:
刚开始执行线程里面while循环的时候,isRun没有值,这个时候,它会从主内存中,把值为isRun给read&load出来,这个时候程序每次执行,都会从自己的线程栈中,获取isRun的值,过了一会儿,你系统把主内存中的字段isRun改为true之后。
不好意思,我本地已经把isRun值缓存下来,这个时候你更新,对于这个线程来说并不重要,而且你也没有通知我要从内存中重新拉取数据。
到这里差不多大家就已经懂了!对于线程来说,它每次都会优先读取线程栈里面的变量值,读取不到,才会从主内存中获取变量值。
三.出现这种问题,如何解决呢?
1.synchronized
给需要执行的代码块加上synchronized关键字,这个时候,执行的代码就会被加上锁,你只有获取到线程锁,你才能继续执行该方法块。
public void run() {
//启动线程执行我的另外一个方法
Long i = 0L ;
while (TestMutiThread.isRun){
synchronized (this){
i++;
}
}
System.out.println("count值为:"+ i );
}
2.volatile
强制你从主内存中读取最新的变量值。
将isRun的值添加volatile关键字。
private static volatile boolean isRun = true;
//程序再执行该段代码的时候,强制从主内存中获取数据
while (TestMutiThread.isRun){
i++;
}
这个就是synchronized和volatile的基本区别。