单例模式(Singleton Pattern)典型的四种实现方式

一、简介:

引入百度百科对单例模式的介绍:

单例模式(Singleton Pattern)是一种常用的软件设计模式。《设计模式》一书中对其介绍:“保证一个类仅有一个实例,并提供一个访问它的全局访问点。”
在某些时候,一个系统只有一个实例是很重要且必要的,比如:Windows系统中的任务管理器, 同时只能存在一个,因为系统瞬态是固定的,存在多个任务管理器也是在浪费资源。

优点:

  1. 在内存里只有一个实例,减少了内存的开销,尤其是频繁的创建和销毁实例(比如管理学院首页页面缓存)。
  2. 避免对资源的多重占用(比如写文件操作)。

缺点

  1. 没有接口,不能继承,与单一职责原则冲突,一个类应该只关心内部逻辑,而不关心外面怎么样来实例化。

二、单例模式的实现(Java):
  • 这里只介绍典型的四种实现方式,懒汉、饿汉、双检锁、登记式/静态内部类。至于其他变种也都是在此基础上变化的,看多了反而凌乱。
  • 实现单例注意3个点:1.单例类只能有一个实例(构造函数私有化)。2.单例类必须自己创建自己的唯一实例。3.暴露给外部一个访问点。

1.懒汉模式:

  • 多个线程可能同时进入if中,最终会创建多个实例,单线程情况下可以使用
  • 懒汉模式线程不安全,但是有人会想,直接在getInstance()方法加个synchronized关键字不就好了?确实,这种写法是能保证多线程安全,但是线程每次获取实例时,都需要先拿到锁,影响效率。
    /**
     * 延迟加载,线程不安全
     */
     private static Singleton instance;
     private Singleton(){}
     public static Singleton getInstance(){
         if(instance==null){
             instance = new Singleton();
         }
         return instance;
     }

2.饿汉模式:

  • 基于 ClassLoader 机制避免了多线程的同步问题,但是在类加载时就创建了实例,浪费了内存。
  • java中的Runtime类就是一个典型的单例实现,它记录了java程序运行时的环境,且允许应用程序与应用程序正在运行的环境进行交互。
    /**
     * 无延迟加载,线程安全
     */
     private static final Singleton instance = new Singleton();
     private Singleton() {}
     public static Singleton getInstance() {
         return instance;
     }

3.双检锁模式:

  • 这种方式采用双锁机制,安全且在多线程情况下能保持高性能。
  • volatile 关键字作用主要是防止 instance = new Singleton() 指令重排,因为这句代码不是一个原子操作,而是①new Singleton()堆中分配内存②初始化Singleton成员变量③instance指向内存中刚开辟出的空间,如果不加volatile关键字,那么执行顺序①②③,由于指令重排可能变为①③②,当执行完①③之后,如果被另一个线程抢占了资源,那么判断instance==null时,结果为false,然后会直接返回instance,此时未初始化,导致使用时可能会报错。
  • -
      /**
       * 延迟加载,线程安全
       */
       private static volatile Singleton instance;
       private Singleton(){}
       public static Singleton getInstance(){
           //第一次检测,避免每次调用getInstance()时都需要获取同步锁
           //提高了效率
           if(instance==null){ 
               //this
               synchronized(Singleton.class){
                   //第二次检测,保证多线程下安全,因为可能多个
                   //线程同时进入this位置。
                   if(instance==null){
                       instance = new Singleton();
                   }
               } 
           }
           return instance;
       }

4.登记式/静态内部类:

  • 这种方式同样利用了 classloder 机制来保证初始化 instance 时只有一个线程,因为 SingletonHolder 类没有被主动使用,只有通过显式调用 getInstance 方法时,才会显式装载 SingletonHolder 类,从而实例化 instance。
  /**
   * 延迟加载 多线程安全
   */
   private Singleton(){}
   private static class InnerSingleton{
      private  static final Singleton INSTANCE = new Singleton(); 
   }
   public static final Singleton getInstance(){
     return   InnerSingleton.INSTANCE;
   }
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值