java volatile
Posted Delta
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了java volatile相关的知识,希望对你有一定的参考价值。
volatile可以保证变量的可见性
当一个变量定义为volatile后,此变量对所有的线程具有可见性。这里的可见性是指当一个线程修改了这个变量的值,新值对于其他线程来说是可以立即得知的。
每次使用volatile变量前都必须先从主内存刷新最新的值,这保证能看见其他线程对变量所做的修改后的值。每次修改volatile变量后都必须同步回主内存,这保证其他线程可以看到自己对变量所做的修改。正是这两条规则保证了volatile变量的可见性。
volatile可以保证有序性
volatile可以禁止指令重排序优化,重排序是指编译器和处理器为了优化程序性能而对指令序列进行排序的一种手段。但是重排序也需要遵守一定规则,重排序操作不会对存在数据依赖关系的操作进行重排序。比如:a=1;b=a; 这个指令序列,由于第二个操作依赖于第一个操作,所以在编译时和处理器运行时这两个操作不会被重排序。但是在多线程环境下,可能出现问题。如下示例:
Map configOptions; volatile boolean initialized = false; // 以下代码在线程A中执行 // 线程A完成配置信息后,initialized改为true configOptions = new HashMap(); processConfigOptions(configOptions); initialized = true; // 以下代码在线程B中执行 // 等待initialized为true,表示线程A已完成配置 while (!initialized) { sleep(); } // 线程A完成配置后,线程B可以开始doSomething(); doSomething();
initialized必须定义为volatile,否则可能出现线程A先赋值initialized为true,而后执行配置。
volatile保证了在赋值initialized之前,先执行完其前面的代码。
volatile 性能
volatile 的读性能消耗与普通变量几乎相同,但是写操作稍慢,因为它需要在本地代码中插入许多内存屏障指令来保证处理器不发生乱序执行。
volatile在并发下运算是不安全的
如下示例,20个线程分别将变量race自加100次,运算结果race的值小于20000 。
public class VolatileTest { public static volatile int race; public static void increase() { race++; } private static final int threads_count = 20; public static void main(String[] args) { Thread[] threads = new Thread[threads_count]; for (int i=0; i<threads_count; i++) { threads[i] = new Thread( new Runnable() { @Override public void run() { for (int i=0; i<100; i++) increase(); } } ); threads[i].start(); } System.out.println(race); } }
以上是关于java volatile的主要内容,如果未能解决你的问题,请参考以下文章
Java:volatile如何保证这段代码中“数据”的可见性?