volatile关键字的作用
1.可以保证不同线程间volatile变量的一致性。但是不能保证原子操作。
2.可以禁止指令重排。
一致性
cpu会将经常使用的值加入到缓存中从而加快读取速度。每次修改变量的值时,首先会在缓存中完成修改,此时内存中的值还没有改变。(至于什么时候写回内存则不确定(会在合适的时候)这样就会出现并发问题)。用volatile修饰的变量会在值改变后,立即修改内存中的值。从而保证不同线程间volatile值的一致性。
例子
用volatile修饰
public class Test1 {
//用volatile修饰
volatile int temp = 0;
int i = 0;
public static void main(String[] args) throws InterruptedException {
Test1 t1 = new Test1();
Thread thread1 = new Thread(()->{
t1.fun1();});
Thread thread2 = new Thread(()->{
t1.fun1();});
Thread thread3 = new Thread(()->{
t1.fun1();});
Thread thread4 = new Thread(()->{
t1.fun1();});
thread1.start();
thread2.start();
thread3.start();
thread4.start();
Thread.sleep(1000);
t1.temp = 1;
}
void fun1(){
while (temp==0){
}
}
}
上述程序可以结束
volatile int temp = 0;改成int temp = 0;后此程序将一直循环下去。
禁止指令重排
JVM可以通过改变指令的执行顺序从而加快执行效率。(保证在本线程中的执行结果不变)
例子
public class Test3 {
//双端检索模式中用volatile防止指令重排
volatile static Test3 t3;
static Test3 getTest3(){
if(t3==null){
synchronized (Test3.class){
if(t3==null){
t3 = new Test3();
}
}
}
return t3;
}
}