Volatile
Volatile 是 java 虚拟机提供轻量级的同步机制
有三点:
1、保证可见性;
2、不保证原子性;
3、禁止指令重排
1、保证可见性
package com.zkw.JUC并发编程.tvolatile;
import java.util.concurrent.TimeUnit;
public class JMMDemon {
// 不加 volatile 线程对主内存的变化不知道,程序会变成死循环
// 加 volatile 可以保证可见性
private volatile static int num = 0;
public static void main(String[] args) {
new Thread(()->{
while (num==0){
}
}).start();
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
num = 1;
System.out.println(num);
}
}
2、不保证原子性
原子性:不可分割
线程A执行任务的时候,不能被打扰,也不可别分割,要么同时成功,要么同时失败
package com.zkw.JUC并发编程.tvolatile;
//不保证原子性
public class VDemon2 {
private volatile static int num = 0;
public static void add(){
num++;
}
public static void main(String[] args) {
for (int i = 1; i <= 20; i++) {
new Thread(()->{
for (int i1 = 0; i1 < 1000; i1++) {
add();
}
}).start();
}
while(Thread.activeCount()>2){
Thread.yield();
}
System.out.println(Thread.currentThread().getName()+" "+num);
}
}
通过命令 javap -c VDemon2
把VDemon2的class文件反编译成字节码文件可以看出,为什么 num++ 只有一行,但是它却可以被多个线程同时操作。
2.1、如果不加 lock 和 synchronized,怎样保证原子性
可以使用原子类来解决
package com.zkw.JUC并发编程.tvolatile;
import java.util.concurrent.atomic.AtomicInteger;
//不保证原子性
public class VDemon2 {
private volatile static AtomicInteger num = new AtomicInteger();
public static void add(){
//num++ //不是一个原子性操作
num.getAndIncrement(); //AtomicInteger +1 方法
}
public static void main(String[] args) {
for (int i = 1; i <= 20; i++) {
new Thread(()->{
for (int i1 = 0; i1 < 1000; i1++) {
add();
}
}).start();
}
while(Thread.activeCount()>2){
Thread.yield();
}
System.out.println(Thread.currentThread().getName()+" "+num);
}
}
3、指令重排
volatile可以避免指令重排:
内存屏障,CPU指令,作用:
1、保证特定的操作的执行顺序!
2、可以保证某些变量的内存可见性(利用这些特性volatile实现了可见性)
Volatile 是可以保持 可见性。不能保证原子性,由于内存屏障,可以保证避免指令重排现象产生