02-单例模式

单例模式

一、定义

确保某一个类只有一个实例,并且自行实例化并向整个系统提供这个实例

二、优点

  1. 减少内存开支。特别是一个对象需要频繁的创建、销毁时,并且创建或销毁时性能有无法优化。
  2. 减少了系统的性能开销。当一个对象的产生需要较多的资源时,如读取配置,产生其他依赖对象等。
  3. 避免对资源的多重占用,例如写文件动作,如果只有一个实例在内存中,可以避免对同一个资源文件的同时写操作
  4. 可以在系统设置全局的访问点,优化和共享资源访问

三、缺点

  1. 单例模式一般没有接口,扩展困难
  2. 测试困难,在并行开发环境中,如果单例模式没有完成,是不能进行测试的
  3. 单例模式与单一职责原则有冲突。

四、使用场景

  1. 要求生成唯一序列号的环境
  2. 在整个项目中需要一个共享访问点或共享数据
  3. 创建一个对象需要消耗的资源过多
  4. 需要定义大量的静态常量和静态方法的环境,如工具类

五、注意事项

  1. 在高并发的情况下,要注意单例模式的线程同步问题
  2. 考虑对象的复用
  3. 坏单例模式

六、单例类型

1. 饿汉模式

饿汉模式其实就是一种预加载机制,在使用前就完成对象的实例化

  • 示例

    public class Singleton {
      private static final Singleton INSTANCE = new Singleton();
    
      private Singleton() {
      }
    
      public static Singleton getInstance() {
          return INSTANCE;
      }
    }
    
  • 优点

    • 实现简单,避免了线程同步

    • 如果单例对象的实例化比较耗时,调用时可以做到快速使用,无需再在实例化上花费太多时间

  • 缺点

    在类加载时就完成了实例化,如果一直没有用到这个实例,就会造成内存浪费

2. 懒汉模式(不同步)

懒汉模式其实就是懒加载的意思,在使用时再进行实例化,不用则不创建对象

  • 示例

    public class Singleton2 {
        private static Singleton2 singleton;
    
        private Singleton2() {
        }
        public static Singleton2 getInstance(){
            if (singleton== null){
                singleton=new Singleton2();
            }
            return singleton;
        }
    }
    
  • 优点

    实现了懒加载,在不使用时节省内存

  • 缺点

    线程不安全,在高并发下不能保证全局单例

3.同步方法

通过同步方法加锁,使其线程安全

  • 示例

    public class Singleton3 {
        private static Singleton3 singleton;
    
        private Singleton3() {
        }
        public synchronized static Singleton3 getInstance(){
            if (singleton== null){
                singleton=new Singleton3();
            }
            return singleton;
        }
    }
    
  • 优点

    通过简单的添加了synchronized关键字就显示了线程安全

  • 缺点

    同步方法效率低,每次访问getInstance()都需要同步,而实际上只要第一次调用需要执行实例化时同步就可以了

4.同步代码块

将同步方法换成同步代码块,以增加调用getInstance方法的效率

  • 示例

    public class Singleton4 {
        private static Singleton4 singleton;
    
        private Singleton4() {
        }
    
        public static Singleton4 getInstance() {
            if (singleton == null) {
                synchronized (Singleton4.class) {
                    singleton = new Singleton4();
                }
            }
            return singleton;
        }
    }
    
    
  • 优点

    同步方法换成同步代码块,以增加调用getInstance方法的效率

  • 缺点

    并不能保证实例的全局唯一性,当一个线程进入了if (singleton == null)判断语句内,还未进行实例化,此时另一个线程获得了执行机会

    将会导致第二个线程进入if语句块,最后导致多次实例化

5.双检锁

通过两次判空的方式优化第四个方法

  • 示例

    public class Singleton5 {
        private static  Singleton5 singleton;
    
        private Singleton5() {
        }
    
        public static Singleton5 getInstance() {
            if (singleton == null) {
                synchronized (Singleton5.class) {
                    if (singleton == null) {
                        singleton = new Singleton5();
                    }
                }
            }
            return singleton;
        }
    }
    
  • 优点

    提升了getInstance的效率

  • 缺点

    不能真正保证线程安全,实例化一个对象分为三步,1.分配内存空间、2.初始化对象、3.将对象指向刚分派的内存空间,但有的编译器为了性能问题,会将第2步跟第3步进行重排序,可能会发生一个线程走了1,3步,此时第二个线程获得执行权,走到if语句块发现singleto不为null,然后将实例取出并进行操作,而实际上实例并没有初始化,就会出现问题。

6.带volatile关键字的双检锁

通过双检索的方式优化第四个方法

  • 示例

    public class Singleton6 {
        private static volatile Singleton6 singleton;
    
        private Singleton6() {
        }
    
        public static Singleton6 getInstance() {
            if (singleton == null) {
                synchronized (Singleton6.class) {
                    if (singleton == null) {
                        singleton = new Singleton5();
                    }
                }
            }
            return singleton;
        }
    }
    
  • 优点

    volatile确保了指令执行顺序,不会重排序

    既可以保证线程安全,有提升了getInstance的效率

  • 缺点

    volatile关键字在Java 5 以前不能确保代码的执行顺序,只有Java 5及之后的jvm才能确保结果正常

7.静态内部类

通过静态内部类的方式实现懒加载,与线程安全

  • 示例

    public class Singleton7 {
    
        private Singleton7() {
        }
    
        public static Singleton6 getInstance() {
            return Holder.INSTANCE;
        }
    
        private static class Holder {
            private static Singleton7 INSTANCE = new Singleton7();
        }
    }
    
  • 优点

    巧用jvm的类加载机制,即实现了懒加载,还保证了线程的安全性,并且保证了实例的唯一性,强烈推荐使用

8.枚举
  • 示例

    public enum Singleton8 {
        INSTACE;
    
        private Singleton8() {
        }
    
    }
    
  • 优点

    实现简单、不仅能避免多线程同步问题,而且还能防止反序列化重新创建新的对象

  • 缺点

    枚举是在JDK 1.5后加入的,1.5前的版本无法使用

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值