Java设计模式————单例模式

单例模式

       单例模式是最常用的设计模式,具有容易理解、使用简便的特点,它主要涉及一个单一的类,该类负责创建自己的对象,同时确保这个类只有单个对象被创建。Spring管理的bean默认都是单例的。

       单例模式的实现非常简单,只由单个类组成。为了确保单例实现的唯一性,单例的构造方法都要被声明为private,再通过static方法实现全局访问获得该单例实例。

        单例模式的实现有以下几种写法:

  • 饿汉式写法
  • 懒汉式写法(线程不安全)
  • 双重校验的同步锁式写法
  • 静态内部类写法
  • 枚举实现写法
  1. 饿汉式写法

    //饿汉式写法(静态常量)
    class Singleton{
        //本类内部创建对象实例
        private final static Singleton SINGLETON = new Singleton();
    
        //构造方法私有化,外面不能new了
        private Singleton(){}
    
        //提供一个公有的静态方法,返回对象实例
        public static Singleton getInstance(){
            return  SINGLETON;
        }
    
    }
    //饿汉式写法(静态代码块)
    class Singleton2{
        //本类内部创建对象实例
        private final static Singleton2 SINGLETON ;
    
        static {
            SINGLETON = new Singleton2();
        }
    
        //构造方法私有化,外面不能new了
        private Singleton2(){}
    
        //提供一个公有的静态方法,返回对象实例
        public static Singleton2 getInstance(){
            return  SINGLETON;
        }
    
    }

            饿汉式写法是线程安全的,不管是不是在多线程环境下,它都只会在类加载的时候实例化一次 。但是,如果整个程序中你没有用到这个实例,就会造成这部分内存的浪费,所以,就有了下面的懒汉式写法,它只会在你需要用到这个实例的情况下才会进行实例化一次。

  2. 懒汉式写法

    //懒汉式写法(线程不安全),开发不推荐使用
    class Singleton{
        //本类内部声明对象实例
        private static Singleton SINGLETON ;
    
        //构造方法私有化,外面不能new了
        private Singleton(){}
    
        //提供一个公有的静态方法,当使用该方法的时,才会去创建对象实例
        public static Singleton getInstance(){
            if (SINGLETON == null){
                SINGLETON = new Singleton();
            }
            return  SINGLETON;
        }
    
    }

           懒汉式写法虽然消除了内存浪费的问题,但却是线程不安全的,只能在单线程环境下使用,如果在多线程环境下,一个线程通过了if (SINGLETON == null)语句的判断,但是还来得及实例化对象,这时候又有一个线程通过了if (SINGLETON == null)语句的判断,这样就不能保证实现单例模式了。

             还有一种写法,为了解决懒汉式写法的线程不安全问题,引入了同步代码块来解决。

    //懒汉式写法(线程安全,同步代码块) 效率太低,开发不推荐使用
    class Singleton2{
        //本类内部创建对象实例
        private static Singleton2 SINGLETON ;
    
        //构造方法私有化,外面不能new了
        private Singleton2(){}
    
        //提供一个公有的静态方法,当使用该方法的时,才会去创建对象实例
        //加入同步代码块,解决线程不安全问题
        public static synchronized Singleton2 getInstance(){
            if (SINGLETON == null){
                SINGLETON = new Singleton2();
            }
            return  SINGLETON;
        }
    
    }

           这样虽然解决了线程不安全的问题,但同步代码块会使开发效率变得很低。这就有了下面的加入了双重校验的同步锁检查写法,即能保证了线程安全,又保证了效率。

  3. 双重校验的同步锁式写法 

    //双重检查
    class Singleton{
    
        private static volatile Singleton SINGLETON ;
    
        private Singleton(){}
    
        //加入双重检查代码,解决线程安全问题,同时解决懒加载问题
        public static  Singleton getInstance(){
            if (SINGLETON == null){
                synchronized (Singleton.class){
                    if(SINGLETON == null){
                        SINGLETON = new Singleton();
                    }
                }
            }
            return  SINGLETON;
        }
    
    }

            这样可以保证用来检查实例是否被创建的代码是线程同步的 ,也就是说这段代码块在同一时刻只能被一个线程执行,但是,同步锁只有在实例没有创建的时候才会起作用,如果单例已经被创建成功,那么任何线程都能通过非同步的方式获取当前实例。注意这里进行了两次SINGLETON == null的校验,第一次的SINGLETON == null的判断是为了避免没必要的加锁,第二次的判断是保证在同步代码块里实现单例

  4. 静态内部类写法

    //静态内部类,推荐使用
    class Singleton{
    
        private Singleton(){}
    
        //使用静态内部类来实例化对象
        private static class SingletonInstance{
            private static final Singleton SINGLETON = new Singleton();
        }
    
        public static Singleton getInstance(){
            return  SingletonInstance.SINGLETON;
        }
    
    }

            静态内部类的特点是,在外部类加载的时候并不会立刻加载内部类,只有在调用到getInstance()的时候,使用到了静态内部类,虚拟机才会去加载该内部类。这种写法也能保证线程安全、也能保证实现单例模式、同时也用到了懒加载

  5. 枚举写法

    //枚举实现单例,推荐使用
    enum Singleton{
        INSTANCE;
    }

    枚举类型是线程安全的,并且只会装载一次,可以利用这个特性来实现单例模式

    接着只要通过

     Singleton instance = Singleton.INSTANCE;

     就可以获得单例模式的实例了

         

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值