• 单例模式的安全写法


            要想知道怎么写单例模式,那么必须得知道什么是单例模式。单例模式是一种设计模式,它确保某个类只有一个实例,并且提供一个全局访问该实例的方法。单例模式不会创建实例副本,而是返回对已创建实例的引用。单例模式的创建可以分为两类。第一类是饿汉式单例模式,它在类加载时就创建了唯一的实例对象,并在全局范围内提供访问点。第二类是懒汉式单例模式,它在首次使用时才创建实例对象,以节省资源。需要注意的是,懒汉式单例模式在多线程环境下需要考虑线程安全性。

    class Student2{
        private static Student2 student = new Student2();//饿汉模式
        private Student2(){
            ;
        }
        public static Student2 getStudent(){
            return student;
        }
    }

    因为要在使用时创建,那么就应该在获取的时候创建,并且获取时,得先判断,是否已经创建好了,如果没有的话,则就是首次调用,得创建实例,如果有的话,就应该使用创建好的。

    class Student3{
        private static Student3 student3 = null;
        private static Object locker = new Object();
        private Student3(){}
        public static Student3 getStudent3(){
            if (student3 == null) {student3 = new Student3();}
            return student3;
        }
    }

    咋看没有问题,实际问题很大。如果有多个线程同时使用该方法,这不就是多个线程同时修改同一个变量的问题吗?那么是否会因为都判定为是首次创建,而导致创建了多个实例呢?答案不言而喻。为了保证线程安全,因此得需要锁。那么就可以这样做:

    class Student3{
        private static Student3 student3 = null;
        private static Object locker = new Object();
        private Student3(){}
        public static Student3 getStudent3(){
            synchronized (locker){
                if (student3 == null) {student3 = new Student3();}
            }
            return student3;
        }
    }

    这样虽然解决了线程安全问题,不过每次判定是否需要创建时,都需要进入锁中,进入就会导致阻塞。倘若已经不是首次调用了,那么这个代码就会带来不小的开销。为什么呢?因为如果不是第一次使用了,那么就不需要创建了,也就不需要修改变量,因此就算此时没加锁并且有多个线程来使用该方法,也不会造成线程安全问题。不过因为此时仍然有锁,这就导致多线程时使用该方法会有线程在这堵塞,而且频繁的加锁解锁也会造成不必要的开销,因此得解决这个问题,要想解决这个问题,就必须进行再一次的判定来决定是否需要加锁,那么是否需要加锁的条件是什么呢?肯定时是否是第一次使用该方法啊,如果是的话,就需要加锁,如果不是,就不需要加锁并且可以直接返回该实例,同时不能确定这里是否存在内存可见性问题,因此最好加上volatile,因此代码可以如此的该:

    class Student3{
        private static volatile Student3 student3 = null;
        private static Object locker = new Object();
        private Student3(){}
        public static Student3 getStudent3(){
            if (student3 == null){//判断是否需要加锁
                synchronized (locker){
                    if (student3 == null) {student3 = new Student3();}//判断
                }
            }
            return student3;
        }
    }

  • 相关阅读:
    山西电力市场日前价格预测【2023-10-01】
    kafka笔记要点和集群安装、消息分组、消费者分组以及与storm的整合机制
    操作系统:存储器管理 练习题(带有详细答案解析)
    【系统设计系列】异步和网络通信
    Allegro基本规则设置指导书
    No6.从零搭建spring-cloud-alibaba微服务框架,实现数据库调用、用户认证与授权等(二,no6-2)
    web蓝桥杯真题:展开你的扇子
    【无标题】
    malloc和new的本质区别
    经典算法(查找与排序)
  • 原文地址:https://blog.csdn.net/LTY3301398968/article/details/132928335