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");
    }
}

posted on 2023-02-20 07:44  王景迁  阅读(14)  评论(0编辑  收藏  举报

导航