volatile adj.易变的;无定性的
C语言、C++、C#和Java语言中都有volatile,它被用来解决多线程环境下共享变量的不一致性。
JDK1.2 之前线程是直接在主存(即共享内存)中读取变量的,所以不存在变量的不一致性,但当前的java内存模型,经过优化,每一个线程都会持有一个工作内存用来存放主存的变量副本,加快速度,这样回导致一个线程对变量进行修改(还未写回内存),但另一个线程看到的是变量的旧值,造成数据的不一致。
要解决这个问题,就需要把变量声明为 volatile,这就指示 JVM,这个变量是不稳定的,每次使用它都到主存中进行读取。
public class MyThread implements Runnable {
static int i=10;
int index;
public MyThread(int index) {
// TODO Auto-generated constructor stub
this.index = index;
}
@Override
public void run() {
// TODO Auto-generated method stub
System.out.println("第"+index+"个线程"+":"+i--);
}
}
public static void main(String[] args) {
Set<Thread> set = new HashSet<>();
for(int i=0;i<10;i++) {
set.add(new Thread(new MyThread(i)));
}
for (Iterator iterator = set.iterator(); iterator.hasNext();) {
Thread thread = (Thread) iterator.next();
thread.start();
}
}
创建10个线程,线程有一个共享变量i(=10),每个线程输出i的值后减1.
结果输出了两次10
A线程读取了i的值进行 i 减1前,B线程获得了cpu的时间片并读取了i,所以才会输出了两次10。
使用volatile关键字修饰变量i
volatile static int i=10;
结果没有再次出现“脏”数据。
volatile能保证变量的可见性,即每一个线程看到(获得)的变量的值都是一致的。
内部原理是通过内存屏障,插入读写屏障禁止指令重排序,但是不具备原子性。