Java中写双重检查加锁的单例时volatile关键字作用

1.保证多进程情况下变量的可见性
(1)可见性是java内存模型的概念性规范;指令重排是导致没有可见性的原因之一.
(2)什么是可见性参加如下demo:

/**
 * 注意:该demo 展示了volatile变量在主内存和线程工作内存中的状态
 * 1.一个线程获取回来的volatile变量会保持不变;除非重新获取一次
 * 2.另外一个线程a改变了volatile变量的值,会立即同步到主内存; 当其他线程重新获取的时候,a对变量的改变可以被看到,这就是可见性.
 *
 */
public class MainActivity extends AppCompatActivity {



    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        Button button = findViewById(R.id.button);
        button.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                //主线程获取test并打印值
                Test test = Test.getTest();
                Log.e("TAG", test.toString());

                // 2.MyThread1获取test,sleep 2000ms后打印值
                MyThread1 t1 = new MyThread1();
                t1.start();

                // 2.MyThread 重置Test,并打印值
                MyThread t = new MyThread();
                t.start();

            }
        });



    }

    static class MyThread extends Thread {

        @Override
        public void run() {
            Test test = Test.resetTest();
            System.out.println("重置volatile变量为null");
            System.out.println(test);
        }


    }

    static class MyThread1 extends Thread {

        @Override
        public void run() {
            Test test = Test.getTest();
            System.out.println("刚获取后 打印volatile变量");
            System.out.println(test);
            try {
                Thread.sleep(2000);
                System.out.println("sleep 了2000ms后 打印volatile变量");
                System.out.println(test);
                System.out.println("sleep 了2000ms后 打印Test中的volatile变量");
                System.out.println(Test.test);
                System.out.println("sleep 了2000ms后 再次获取test后打印volatile变量");
                System.out.println(Test.getTest());

            } catch (InterruptedException e) {
                e.printStackTrace();
            }


        }


    }





    static class Test {

        private int mT;

        private static volatile Test test;

        private Test() {

        }

        public static Test getTest() {
            if (test == null) {
                test = new Test();

            }
            return test;
        }

        public static Test resetTest() {
            test = null;
            return test;
        }

    }
}

运行结果如下:

2020-07-07 14:05:48.530 4772-4772/com.example.myapplication E/: com.example.myapplication.MainActivity$Test@d28ed69
2020-07-07 14:05:48.531 4772-4945/com.example.myapplication I/System.out: 刚获取后 打印volatile变量
2020-07-07 14:05:48.532 4772-4945/com.example.myapplication I/System.out: com.example.myapplication.MainActivity$Test@d28ed69
2020-07-07 14:05:48.532 4772-4946/com.example.myapplication I/System.out: 重置volatile变量为null
2020-07-07 14:05:48.532 4772-4946/com.example.myapplication I/System.out: null
2020-07-07 14:05:50.532 4772-4945/com.example.myapplication I/System.out: sleep 了2000ms后 打印volatile变量
2020-07-07 14:05:50.533 4772-4945/com.example.myapplication I/System.out: com.example.myapplication.MainActivity$Test@d28ed69
2020-07-07 14:05:50.533 4772-4945/com.example.myapplication I/System.out: sleep 了2000ms后 打印Test中的volatile变量
2020-07-07 14:05:50.533 4772-4945/com.example.myapplication I/System.out: null
2020-07-07 14:05:50.533 4772-4945/com.example.myapplication I/System.out: sleep 了2000ms后 再次获取test后打印volatile变量
2020-07-07 14:05:50.533 4772-4945/com.example.myapplication I/System.out: com.example.myapplication.MainActivity$Test@6e8a08f

参考:
1.http://www.cs.umd.edu/~pugh/java/memoryModel/jsr133.pdf
2.http://ifeve.com/wp-content/uploads/2014/03/JSR133%E4%B8%AD%E6%96%87%E7%89%881.pdf
3.https://jcp.org/en/jsr/overview
4.JCP
https://zh.wikipedia.org/wiki/JCP

2.禁止 instance = new Singleton();的指令重排
注意:
instance = new Singleton()
分解为:
1.分配对象内存空间
2.初始化对象
3.将instance指向分配的内存空间
若不加 volatile;2和3两个步骤可以指令重排;这样就会造成Instance指向了内存空间,但实际未完成对象初始化.

这样会导致a线程只执行到:Instance指向了内存空间,但实际未完成对象初始化;
的时候b线程判断instance != null 而返回一个未完成初始化化的对象.

参考:
1.Java单例模式双重检查锁定中volatile关键字的作用
https://blog.csdn.net/zcl_love_wx/article/details/80758162

2.单例模式双重检查加锁为什么需要加上volatile关键字?
https://blog.csdn.net/fd2025/article/details/103837840

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值