平时工作中对于多线程的应用并不太多,但是不能说工作中不应用就可以对此不去了解,至少要做的知道有这么个东西,主要是作什么的,这样有助于看其它人写的代码。提到这个volatile,一般都会想到并发,同步,锁之类,但要想搞清楚需要看看下面一些知识。

高速缓存的作用是什么?
由于处理器与主内存在处理数据的速度上有数量级的差异,所以引入了比主内存速度更快的高速缓存。处理器从主内存中读取数据放到高速缓存中做交互运算,最后回写到主内存中。
引入高速缓存会带来哪些问题?

这是JAVA内存模型范畴,主要是用来屏蔽硬件与系统的内存访问差异,让JAVA程序可以在不同的平台上达到相同的内存访问效果。
这里说的工作内存,主内存与JVM内存中讲的JAVA堆,栈,方法区不是同一层次上的概念,需要区分。
主要是工作内存与主内存之间的具体交互协议,即一个变量是如何从主内存加载到工作内存,然后从工作内存如何同步到主内存的具体实现细节,总共有以下几个操作:

这三个特性是并发操作中需要处理的问题,volatile与下面两个特性有关联。所以在符合可见性以及有序性特性的场景就是volatile的适用场景,也是它的作用所在。

反例,多线程对volatile静态变量执行累加。
这里的count++看起来是一个语句,但对应的字节码不是一条,在执行多条字节码的期间主内存中的值有可能被其它线程所修改,从而导致回写到内存中的值不一致。下面代码的输出并不总是正确。
private static volatile int count=0;
private static void increase(){
    count++;
}
public static void main(String[] args) throws Exception {
    Thread[] threads=new Thread[30];
    for(int i=0;i<threads.length;i++){
        threads[i]=new Thread(new Runnable() {
            @Override
            public void run() {
                for(int k=0;k<10000;k++){
                    increase();
                    System.out.println(count);
                }
            }
        });
        threads[i].start();
        Thread.sleep(1);
    }
}
下面是count++对应的字节码,很明显是多条字节码。volatile只能保证每次读取变量的值是最新的,它在获取到主内存变量后是对其副本进行修改,并不会锁定主内存中的值。
 static void access$000();
    flags: ACC_STATIC, ACC_SYNTHETIC
    Code:
      stack=0, locals=0, args_size=0
         0: invokestatic  #2                  // Method increase:()V
         3: return        
      LineNumberTable:
        line 6: 0
  static int access$100();
    flags: ACC_STATIC, ACC_SYNTHETIC
    Code:
      stack=1, locals=0, args_size=0
         0: getstatic     #1                  // Field count:I
         3: ireturn       
      LineNumberTable:
        line 6: 0
  static {};
    flags: ACC_STATIC
    Code:
      stack=1, locals=0, args_size=0
         0: iconst_0      
         1: putstatic     #1                  // Field count:I
         4: return        
      LineNumberTable:
        line 8: 0
}
某些共享的状态变量是非常适合的,比如dubbo提供的accesslog filter。某些资源只加载一次的场景特别适用,比如应用程序的配置文件的加载,变量的初始化之类。
private volatile ScheduledFuture<?> logFuture = null;
private void init() {
    if (logFuture == null) {
        synchronized (logScheduled) {
            if (logFuture == null) {
                logFuture = ...;
            }
        }
    }
}
由于volatile需要在修改变量时增加内存屏障语句,理所当然的相对没有内存屏障语句的普通变量要慢一些。
volatile的特点是当线程对变量修改后马上回与内存保证可见性,同时禁止重排序保证程序执行的有序性。由于它操作的是副本并不会对主内存加锁,所以并不具体同步语法块以及锁的特点即可一时刻同一变量只允许一个线程操作。
本文主要引用《深入理解JAVA虚似机》
原文:http://www.cnblogs.com/ASPNET2008/p/6391429.html