1、认识Volatile关键字
2、机器硬件CPU与JMM
public class ReaderAndUpdater {
final static int MAX = 50;
static int init_value = 0;
public static void main(String[] args) {
new Thread(() -> {
int localValue = init_value;
while (localValue < MAX) {
if (localValue != init_value) {
System.out.println("The init_value: " + init_value);
localValue = init_value;
}
}
}, "Reader").start();
new Thread(() -> {
int localValue = init_value;
while (localValue < MAX) {
System.out.println("The init_value will be change to : " + (++localValue));
init_value = localValue;
try {
TimeUnit.SECONDS.sleep(2);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}, "Updater").start();
}
}
3、Volatile关键字的语义分析
作用:让其他线程能够马上感知到某一线程对某个变量的修改。
保证可见性:对共享变量的修改,其他的线程能马上感知到。
保证有序性:
重排序(编译阶段、指令优化阶段)
输入程序的代码顺序并不是实际执行的顺序。
重排序后对单线程没有影响,对多线程有影响。
不能保证原子性:读、写(i++)
Volatile规则:
对于Volatile修饰的变量,其之前的代码不能调整到它的后面去,其后面的代码也不能调整到它的前面去。
Volatile的原理和实现机制(轻量级锁)
public class InCreaseDemo000 {
static volatile int m = 0;
public static void increase() {
m++;
}
public static void main(String[] args) {
for (int i = 0; i < 10; i++) {
new Thread(()-> {
for (int j = 0; j < 5; j++) {
increase();
}
}).start();
}
System.out.println(m);
}
}
4、Volatile的使用场景
状态标志(开关模式)
public class ShutDownDemo extends Thread {
private volatile boolean started = false;
public void run() {
while(started) {
dowork();
}
}
public void shutdown() {
started = false;
}
}
双重检查锁定(double-checked-locking)
public class Singleton {
private volatile static Singleton instance;
public static Singleton getInstance() {
if (instance == null) {
synchronized(Singleton.class) {
instance = new Singleton();
}
}
}
}
需要利用顺序性
5、Volatile和Synchronized的区别
使用上的区别
Volatile只能修饰变量,而Synchronized可以修饰方法和语句块。
对原子性的保证
Synchronized可以保证原子性,而Volatile不能。
对可见性的保证
两者都可以保证可见性,但是两者的实现原理不同。Volatile是对变量加了lock,而Synchronized使用了monitorEnter和monitorexit,monitor对应JVM的指令。
对有序性的保证
Volatile保证了有序性,Synchronized也可以,但是代价太大(重量级,由并发退化到串行执行)。
其他
Synchronized会引起线程阻塞,而Volatile不会。