volatile 关键字
volatile 是一个类型修饰符,它是被设计用来修饰被不同线程访问和修改的变量。在使用 volatile 修饰成员变量后,所有线程在任何时间所看到变量的值都是相同的。此外,使用 volatile 会影响到编译器对代码的优化,因此会降低程序的执行效率。
volatile 可以保证并发三大安全性的可见性原则
- 每次访问变量时,总是获取主内存的最新值
- 每次修改变量后,立刻写回到主内存中
volatile 的可见性保证不仅对 volatile 修饰的变量生效
- 线程A去写一个 volatile 修饰的变量,线程B随后也要去读这个变量,那么在线程A中所有写变量操作在 volatile 变量之前的对A可见的变量也会对B可见
- 如果线程A去读一个volatile变量,则所有对线程A可见的变量,在线程A读取这个volatile变量时,会从主存中重新读一次
例子:
public class MyClass {
private int years;
private int months
private volatile int days;
public void update(int years, int months, int days){
this.years = years;
this.months = months;
this.days = days;
}
}
// 当days变量被写入时,years和months因为对当前线程可见,也会被写入到主存中
public class MyClass {
private int years;
private int months
private volatile int days;
public int totalDays() {
int total = this.days;
total += months * 30;
total += years * 365;
return total;
}
public void update(int years, int months, int days){
this.years = years;
this.months = months;
this.days = days;
}
}
// totalDays()方法执行时,第一步读取days的值,因为days时volatile变量,所以所有对当前线程可见的变量都会从主存中重新读一次
volatile 的 Happens-Before 原则
- 对其它变量的读和写操作不能被重排序到对一个volatile变量的写操作之后。
- 对其他变量的读和写操作不能被重排序到对一个volatile变量的读操作之前。