一次偶然的机会(java多线程电梯做业寻求多个进程分享变量的方法),接触到了volatile,所以我查阅了相关的材料,对这部分作了一些了解,在这里和你们分享一下。java
首先,咱们先来聊一聊几个概念编程
编译器和JVM经过改变程序的处理顺序来优化程序,用于提升程序性能的方式。缓存
多线程程序设计中,重排序会致使运行错误。多线程
举个栗子:性能
class Compare {
private int x = 0;
private int y = 0;
public void write() {
x = 100;
y = 50;
}
public boolean compare() {
return x<y
}
}
public class Main {
public static void main(String[] args) {
final Compare com = new Compare();
new Thread() {
public void run() {
com.write();
}
}.start();
new Thread() {
public void run() {
com.read();
}
}.start();
}
}
让人吃惊的是,x<y竟然真的存在true的状况优化
缘由就在于重排序this
编译器的优化策略可能会改变x,y的赋值顺序,致使x<yatom
显然,咱们能够经过synchronized来解决这个问题spa
线程A将某个值写入字段x,线程B读到了这个值线程
多线程中的可见性问题来源于normal read/write操做是经过缓存在执行的,read到的不必定是最新值,write的也不必定当即对其余线程可见
而synchronized是解决这一问题的有效方法,相信你们也并不陌生,具体用法能够参考个人另外一篇博客
其实,volatile也是一种不错的方法
不可分割的操做,例如某线程正在执行synchronized方法,其余线程没法进入该方法,从多线程的角度,这就是原子操做。
Java定义了一些原子操做:primitive type(char、int)的赋值和引用,对象等引用类型的赋值和引用
可是long与double的操做不是原子的,在线程共享时须要放入synchronized
Make sure that a given variable is read directly from main memory and always written back to main memory when updated
volatile具备同步处理(参考sunchronization)和对long和double的原子操做这两种功能
一、若是线程A向volatile字段写入的值对线程B可见,那么以前向其余字段写入的值都是对B可见
二、向volatile字段读取和写入先后不会发生重排序
看到这里,咱们发现重排序和可见性的问题好像都被volatile解决了
在这里,咱们来看一段代码,深刻理解一下同步处理
class TryVolatile {
private int num = 0;
private volatile boolean valid = false;
public void write() {
num = 1;
valid = true;
/*
*一、不会被重排序
*二、线程B中valid会为true
*三、线程B可能出现num=1
*/
}
public void read() {
if (valid) {
System.out.println(this.num);
}
}
}
public class Main {
public static void main(String[] args) {
final tryVolatile = new TryVolatile;
new Thread() {
public void run() {
tryVolatile.write();
}
}.start();
new Thread() {
public void run() {
tryVolatie.read();
}
}.start();
}
}
总结一下volatile的使用:
一、volatile字段赋值语句位置很重要!!!(能够运行上面的代码观察
二、volatile不会进行线程互斥处理(volatile字段不会进入等待队列
三、访问volatile字段会产生性能开销(参考synchronized
java.util.concurrent.atomic包提供了原子操做编程的类,例如AtomicInteger、AtomicLong、AtomicIntegerArray等,都是经过封装volatile获得的