大话设计模式之单例模式

目录

1.引入单例模式 

2.什么是叫单例模式?

3. 单例模式包括多少种?

a.饿汉模式(他没吃饱,要快速的吃饱)

b.懒汉模式(他吃饱了,等饿的时候再吃)

c.两者的区别

4.传统单例模式有什么缺点?

5.怎么对传统单例模式进行改进?

a.使用lock进行单重锁定

b.使用lock进行双重锁定


1.引入单例模式 

在开始之前,咱先来考虑一下问题,对于一些对象,我们只需要一个,比如线程池,缓存等,这类对象只能有一个实例,如果制造出多个实例,会出现问题的,如行为异常,资源使用过量等。那这种情况怎么弄呢?

有人说这直接用全局变量不就行了,可是如果用全局的静态变量,那有可能最终程序根本没用到,导致资源的浪费。

那么就要说道下面要说的,单例模式,这个应该是设计模式中最简单的啦。

 

2.什么是叫单例模式?

单例模式就是保证在整个应用中某个实例有且只有一个,不能通过任何方法实现多个实例的创建。

3. 单例模式包括多少种?

a.饿汉模式(他没吃饱,要快速的吃饱)

具体的过程就是先将构造方法私有化,使得外部不能通过new方法创建,然后在类加载的时候,就创建唯一的对象instance,最后提供一个供外部获取实例instance的方法getInstance。

public class SingletonA {
  //1.构造方法私有化,不允许外部直接创建
  private SingletonA(){
  }
  //2.创建类的唯一实例
  private static SingletonA instance=new SingletonA();
  //3.提供一个用于获取实例的方法,采用public static修饰
  public static SingletonA getInstance(){
    return instance;
  }
}

b.懒汉模式(他吃饱了,等饿的时候再吃)

具体的过程就是先将构造方法私有化,使得外部不能通过new方法创建,然后在类加载的时候,声明instance对象,但并不创建,最后提供一个供外部获取实例instance的方法getInstance,如果instance为null,也就是未创建instance对象时,就创建一个对象instance,如果已经创建了instance对象,就直接返回对象。

public class SingletonB {
  //1.构造方法私有化,不允许外部直接创建
  private SingletonB(){
  }
  //2.创建类的唯一实例
  private static SingletonB instance;
  //3.提供一个用于获取实例的方法,采用public static修饰
  public static SingletonB getInstance(){
    if(instance==null){
      return new SingletonB();
    }
    return instance;
  }
}

c.两者的区别

  • 速度方面:

饿汉模式:该模式在类加载的时候,就创建了对象。这样就导致了他加载类的速度慢,因为要创建对象,但是运行时获取对象时速度快,因为类加载的时候已经创建好了,直接使用就行。

懒汉模式:该模式在类加载的时候,只是声明了对象,并没有创建。这样就导致了他加载类的速度快,因为不需要创建对象,但是运行时获取对象时速度慢,因为类加载的时候并没有创建,在运行的时候要创建。

  • 线程安全性方面

饿汉模式:因为在类加载的时候就创建了对象,没有同时加载的情况,所以线程是安全的。

懒汉模式:因为在类运行的时候才创建了对象,存在两个线程同时调用getInstance方法,所以有创建两个对象的可能性,即线程是不安全的。

4.传统单例模式有什么缺点?

前面说了懒汉是线程不安全的。多个线程同时进行时,会造成创建多个实例。

5.怎么对传统单例模式进行改进?

a.使用synchronized进行单重锁定

public class Singleton {
  //1.构造方法私有化,不允许外部直接创建
  private Singleton(){
  }
  //2.创建类的唯一实例
  private static Singleton instance;
  //3.程序运行时创建一个静态只读的进程辅助对象
  private static final Object syncRoot=new Object();

  //3.提供一个用于获取实例的方法,采用public static修饰
  public static Singleton getInstance(){
    //在此处只有一个线程可以进入
    synchronized (syncRoot){
      if(instance==null){
        return new Singleton();
      }
    }
    return instance;
  }
}

缺点:十分影响性能,每次进来都加锁,速度太慢啦。

b.使用synchronized进行双重锁定

public class Singleton {
  //1.构造方法私有化,不允许外部直接创建
  private Singleton(){
  }
  //2.创建类的唯一实例
  private static Singleton instance;
  //3.程序运行时创建一个静态只读的进程辅助对象
  private static final Object syncRoot=new Object();

  //3.提供一个用于获取实例的方法,采用public static修饰
  public static Singleton getInstance(){
    //判断实例是否存在,不存在再进行加锁
    if(instance==null){
      //在此处只有一个线程可以进入
      synchronized (syncRoot){
        if(instance==null){
          return new Singleton();
        }
      }
    }
    return instance;
  }
}

存在两个instance判空的原因:

比如有两个进程A,B,他们同时调用getInstance方法,且instance=null,他们都将通过第一层判断,由于synchronized,只有A进入,并创建了instance对象,如果没有第二层判断,当A退出的时候,又要新建一个instance。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值