volatile关键字在于保证了线程可见性,线程的可见性涉及到Java虚拟机内存模型,用以下例子进行说明:
public class Volatile {
/*volatile*/ static boolean running = true;
public static void threadMethod() {
//4.主线程执行完毕后线程开始执行打印 start thread
System.out.println("start thread");
//5.这时正常情况下running应该为false 并且不进入死循环
while (running) {
}
//6.并且最后打印end thread
System.out.println("end thread");
}
//当启动main方法后
public static void main(String[] args) {
//1.首先会创建线程并调用threadMethod方法
new Thread(Volatile::threadMethod).start();
//2.然后睡眠1秒
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
//3.将running 设置为false
running = false;
}
}
正常情况下应该如上方的注释的顺序进行执行,但是运行结果却如下所示:
start thread
并没有打印end thread,这就涉及到了JMM(Java虚拟机内存模型),在Java虚拟机中运行线程时,涉及到主内存和CPU运行缓冲区,以以上例子做说明,当我们启动线程后读取到的running 的值首先是ture,此时CPU会将该值加载到CPU的线程缓冲区当中,而当运行running = false 后主内存中的值已经发生改变,但是由于running 的值原本是ture从而导致while 循环一直是死循环,但是由于CPU一直忙于while 循环,一直没有空闲时间从主内存中重新进行获取数据导致了CPU缓冲区中的数据一直是ture,从而导致了线程一直无法执行完毕,而volatile关键字在于保证了线程的可见性,当running 发生改变时,将会通知线程数据发生了改变,而线程将从主内存中重新加载数据,并执行,当去掉volatile关键字的注释后运行正常如下所示:
start thread
end thread
volatile关键字保证了线程可见性但是不保证线程原子性,而synchronized关键字既保证了线程的可见性又保证了线程的原子性,但是synchronized关键字的性能比volatile关键字的性能地的多