java中volatile关键字,是可以保证共享变量在线程间具有可见性的,完整的说,即一个线程的写操作,对其他线程可见。什么意思呢? 首先理解可见性,反过来问,为什么共享变量在线程间不是可见的呢(严格说是为什么不总是可见呢)?宏观上理解,根据jmm,各个线程对共享变量拥有自己的工作副本,所有的操作,都是针对工作副本操作的,之后刷新副本到主内存,此时,其他线程才可以看到最新的共享变量。如果某一线程更改共享变量后,还未刷新到主存,而另外一个线程对该变量做读取,那么就读不到新值。但实际上,该问题的产生,是编译器对代码进行重排序引起的,例如,当编译器在不影响代码语意情况下,认为写操作放在后面会更有效,就会进行重排序,如果编译器重排某个操作,那么在该写操作完成之前,其他线程就是对该写操作是不可见的,这反应了对缓存的影响。
深入来说,volatile是通过内存屏障和禁止重排序来保证可见性的:
1. 对volatile进行写操作时,会在写操作之后增加一个store屏障指令
2. 对volatile进行读操作时,会在读操作之前增加一个load屏障指令
简单来说,就是volatile变量进行读时,会有一个主内存到工作内存到拷贝动作,进行写后,会有一个工作内存刷新主内存到动作。
需要说明的是,volatile不保证原子性的,因此相对于synchronized,volatile用的并不广泛,因此volatile的适用场景:
1. 对变量的写入操作,不依赖于当前值:
不满足: number++;number=number+1;
满足:布尔值
2. 该变量不包含在其他volatile变量的不变式中:
不满足:low < up
因此,对于不满足的场景,写操作必须增加同步锁。例如:
private volatile int number;
public int get(){
return number;
}
public synchronized void increase(){
number++;
}