volatile
缓存一致性问题
每个线程都有自己的工作内存。
线程在初始化时从主内存读取所需的变量值到工作内存。
在线程运行时,如果是读取则从工作内存中读取,如果是写入则先写到工作内存再刷新到主内存。
在并发情况下可能出现不同线程持有不同的共享变量值。例如,A线程修改了共享变量值并刷新到主内存,但B、C线程在读取该共享变量值时从本线程的工作内存读取,读取到的值不是最新的。
模拟问题
public class Main extends Thread {
private static boolean flag = false;
public Main(String name) {
super(name);
}
@Override
public void run() {
// 等待1s确保main线程读到的flag是旧值false,否则会读到thread1设置flag后的新值true
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("begin to set flag true");
flag = true;
System.out.println("set flag true end");
}
public static void main(String[] args) throws InterruptedException {
Main thread1 = new Main("thread1");
thread1.start();
while (!flag) {
}
System.out.println("end");
}
}
volatile关键字作用
保证可见性(线程读写直接访问主内存,而不是自己的工作内存)
禁止指令重排序(内存屏障)
不保证线程安全(不能保证对变量的操作是原子性的)
解决问题
flag字段加上volatile
public class Main extends Thread {
private volatile static boolean flag = false;
public Main(String name) {
super(name);
}
@Override
public void run() {
// 等待1s确保main线程读到的flag是旧值false,否则会读到thread1设置flag后的新值true
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("begin to set flag true");
flag = true;
System.out.println("set flag true end");
}
public static void main(String[] args) throws InterruptedException {
Main thread1 = new Main("thread1");
thread1.start();
while (!flag) {
}
System.out.println("end");
}
}