Volatile java的类型修饰符,用来修饰被不同线程访问和修改的变量。volatile的作用是作为指令关键字确保本条指令不会因为编译器的优化而省略,每次都重新读取值。
volatile可以理解为synchronized的一部分保证了并发的可见性,但是并没有保证原子性。也就是说a线程修改了变量的值,能给被b线程知道并读取。但是却不能保证每次只有一个线程来操作变量的值。所以volatile的使用场景要小于synchronized。并且使用synchronized同步的地方并不一定能够使用volatile代替。
volatile变量具有synchronized的可见特性,但是不具备原子特性。这就是说线程能够自动发现volatile变量的最新值。volatile变量可用于提供线程安全,但是只能用于非常有限的一组用例:多个变量之间或者某个变量的当前值与修改后的值之间没有约束。因此,单独使用volatile还不足以实现计数器,互斥锁或任何具有与多个变量相关的不变式(Invariants)的类(例如:”start<=end”)
volatile的使用条件:
变量的写操作不依赖于当前值。
该变量没有包含在其它变量的不变式中。
线程安全计数器:实现n++需要依赖于n的当前值,会出现读,写,读操作,这个操作必须以原子性进行,也就是说在n的值累加期间不能有其它线程再操作n累加,这样会导致结果出错。也就是说实现计数器需要满足并发的原子性,但是volatile不能用作线程安全计数器。
线程安全的值范围:例如不变式start<=end,下界应该总是小于上届。使用volatile来确保线程安全是不可靠的,原因也是只保证了可见性,但是没有保证原子性。
当a线程调用setStart(4),b线程同时调用setEnd(2)时,结果变成了[4-2]这个范围明显是错误的。
public static class VolatileRangeDemo {
private volatile int
start
,
end
;
//[1-5]
public void
setStart(
int value) {
if (value <
end) {
start = value
;
}
}
public void
setEnd(
int value) {
if (value >
start) {
end = value
;
}
}
}
volatile优势:
1.使用简单。
2.在某些情况下性能优于锁。