Java允许线程访问共享变量。作为规则,为了确保共享变量被一致的和可靠的更新,线程应该确保它获得一个排它锁单独的获取这个变量。Java提供了第二种机制即volatile关键字,在某些情况下比锁更加方便。一个字段可以被声明为volatile,在这种情况下,Java内存模型确保所有线程看到的变量值都一样。(Java语言规范)
一个变量被volatile修饰后,这个变量就具备了可见性和禁止指令重排序的特性。
可见性
Java内存模型中分为主存和线程的工作内存,线程的工作内存是私有的,其他线程无法看到。变量都存储在主存中,当线程需要一个变量的时候,首先会从主存中复制变量的副本到工作内存中,所以每个线程都拥有同一个变量得副本,他们对该变量副本的修改并不会影响到其他线程,修改后的变量副本需要写回主内存,这样就会导致有可能写回的值不一样,造成错误。此时可用volatile关键字修饰变量,保证每个线程对变量的修改,其他线程都是立即可见的。
禁止指令重排序
Java执行语句的顺序可能和代码中写的顺序不同,使用volatile关键字,能保证它的执行顺序不会改变。
Volatile和Synchronized
volatile修饰的变量具有可见性和禁止指令重排序特性,只能修饰变量。不具有原子性,使用在类似i++这种操作上是无效的。
synchronized修饰方法和代码块,具有互斥性,内存可见性,原子性。