volatile关键字

2023-03-23  本文已影响0人  sunpy

多线程下的共享变量的问题


  1. 多个线程操作同一变量数据,是否会看到变化的数据。
  2. 多个线程执行同一段程序,会不会中间插手,造成脏数据(多数情况下,我们通过加锁的形式来保证一段程序一个时间段只有一个线程执行)。
  3. 多线程操作时,编译器出于性能考虑,采取指令重排序(处理器的乱序执行),导致多线程程序出现问题
    (指令重排序是编译器处于性能考虑,在不影响单线程程序正确性的
    条件下进行重新排序)。

\color{red}{简单概括就是多线程存在可见性、原子性、有序性的问题。}

volatile实现可见性


未加入volatile关键字引发的可见性问题:

private static boolean flag=false;

public static void test1() {
    System.out.println("========== main thread start test1");

    Thread t1 = new Thread(() -> {
        while (!flag) {

        }
        System.out.println("========== " + Thread.currentThread().getName() + " - flag : " + flag);
    }, "t1");
    t1.start();

    //主线程睡眠100毫秒
    try {
        Thread.sleep(10000);
    } catch (InterruptedException e) {
        e.printStackTrace();
    }

    Thread t2 = new Thread(() -> {
        flag = true;
        System.out.println("==========" + Thread.currentThread().getName() + " - flag : " + flag);
    }, "t2");
    t2.start();
}

结果:线程间数据不可见

加入volatile关键字:

private static volatile boolean flag=false;

结果:

volatile防止指令重排序


未加入volatile关键字引发的指令重排序问题:

private static boolean flag=false;
private static int i = 0;
public static void test2() throws InterruptedException {
    System.out.println("========== main thread start test2");

    for (int a = 0; a < 100000; a++) {
        Thread t1 = new Thread(() -> {
            i = 1;
            flag = true;
        }, "t1");

        Thread t2 = new Thread(() -> {
            if (flag) {
                int j = i * i;
                System.out.println("========== " + Thread.currentThread().getName() + " - j = " + j);
            }
        }, "t2");

        t1.start();
        t2.start();

        i = 0;
        flag = false;
    }
}

配置输出到指定的文件:

结果:线程t1中,flag=true居然先于i=1先执行,打印出来了0。

加入volatile关键字:

private static volatile boolean flag = false;

结果:

为什么在变量flag上面加volatile关键字,而不是在变量i上面?
这就涉及到volatile的内存屏障,简单来说就是:

\color{red}{volatile可以实现可见性、有序性,但是无法提供原子性。}
\color{green}{volatile想要实现原子性,需要配合synchronized锁或者cas锁。}

多线程下的单例模式(double-check-locking双重检查锁定)


思路:利用volatile+synchronized 保证原子性、可见性、有序性

public class SingleObj {

    private static volatile SingleObj singleObj = null;

    private SingleObj() {
    }

    public static SingleObj getInstance() {
        if (null == singleObj) {
            synchronized (SingleObj.class) {
                if (null == singleObj) {
                    singleObj = new SingleObj();
                }
            }
        }

        return singleObj;
    }
}

解释:

多线程下的卖票(cas工具类实现)


public class AiTest {

    private static AtomicInteger atomicInteger = new AtomicInteger(100);

    public static void test4() {
        for (int i = 0 ; i < 100 ; i++) {
            Thread t = new Thread(() -> {
                System.out.println(Thread.currentThread().getName() + "正在出售第" + atomicInteger.getAndDecrement() + "张票");
                ;
            }, "t");
            t.start();
        }
    }

    public static void main(String[] args) {
        test4();
    }
}

参考


https://blog.csdn.net/weixin_42867178/article/details/124431933
https://zhuanlan.zhihu.com/p/133851347

上一篇下一篇

猜你喜欢

热点阅读