volatle关键字:当多个线程操作共享数据时,可以保证内存中的数据可见。相较于synchronized是一种较为轻量级的同步策略。
注意:
1.volatile 不具备"互斥性"
2.不能保证变量的”原子性“
举例说明volatile作用:
public class TestVolatile {
public static void main(String[] args) {
//创建线程
ThreadDemo th = new ThreadDemo();
new Thread(th,"MyThread").start();
//循环等待,flag == true 时会结束循环
while (true){
if(th.isFlag()){
System.out.println("===============");
break;
}
}
}
}
//ThreadDemo实现的线程只将flag修改为true
class ThreadDemo implements Runnable{
private boolean flag = false;
public void run() {
flag = true;
System.out.println("flag==>"+flag);
}
public boolean isFlag() {
return flag;
}
public void setFlag(boolean flag) {
this.flag = flag;
}
}
以上程序很简单,先创建一个线程,将flag由false修改为true,main方法里面有个while循环,只有flag为true时,才会结束循环。
看一下执行结果:
多执行几次会发现出现以上两种结果,第一中程序想入死循环,第二种正常结束。what happend?
因为各个线程为了增加执行速度,都会将会有自己的缓存,先将数据从主存中拷贝过来,修改后在返回给主存。
注意上面1 ,2,3不代表执行顺序
1代表MyThread线程从主从中得到flag初始值false,2代表线程将falg修改完后同步到主存,3代表main线程得到flag的值。
分析第一种为啥会陷入死循环,不是创建的线程已经将flag修改为true了吗,while()循环里为啥不会跳出。原因是新线程还为执行完毕或者说还未将flag修改为true的结果更新到主存中去,mian方法就执行到whlie循环部分,那么在主存中flag值为flase,一直在这里循环,直到cpu时间片被用完。MyThread线程得到cpu执行完毕。但是while(true)执行速度很快,重新得到cpu时间片后,不会从主从中去拿跟新后的flag值,只盯着自己缓存里面为flase的flag,那么陷入死循环。
为了让第一中情况更加明显,可以先让MyThread休眠0.2s,再去修改flag = true;则while循环基本上拿不到主存跟新后的flag。
执行结果基本上会是第一种情况,陷入死循环。
使用volatile修饰flag后,相当于直接在内存中修改flag值,这样while部分拿到的flag值一定为true。
执行结果: