设计模式——单例模式

一、定义
确保一个类只有一个实例,并且提供一个全局变量来访问到这个唯一的实例
二、实现方式
1.饿汉式

public class EagerSingleton{
  private static final EagerSingleton instance = new EagerSingleton();
  //防止在其他类中new出一个对象,可以给构造器加上private访问权限
  private EagerSingleton(){
    
  }
  //向外暴露一个方法,来得到这个类的唯一的对象
  public static EagerSingleton getInstance(){
    return instance;
  }
}

当类被加载的时候,静态变量instance就会被初始化,这个类的唯一实例就会创建。

优点:写法简单,在类加载的时候就会创建出对象,类只会加载一次,那么也就只会创建一次对象,避免了线程安全问题

缺点:(1)不能把控对象创建的时机,因为只要类被加载,这个对象就会被创建,而类的加载不只是使用类的static方法

​ (2)可能会造成内存空间的浪费,也就是说,也跟第一条一样,对象可能会被无意识的创建出来

2懒汉式

public class LazySingleton{
  private static  volatile LazySingleton instance;
  private LazySingleton(){
    
  }
  public static LazySingleton getInstance01(){
    if(instance == null){
      instance = new LazySingleton();
    }
    return instance;
  }
  public static synchronized LazySingleton getInstance02(){
    if(instance == null){
      instance = new LazySingleton();
    }
    return instance;
  }
  public static LazySingleton getInstance03(){
    //第一重判断
    if(instance == null){
      synchronized(LazySingleton.class){
        //第二重判断
        if(instance == null){
          instance = new LazySingleton();
        }
      }
    }
    return instance;
  }
}

懒汉式和饿汉式一样,将构造器设置为私有的,只能在它类的内部创建对象。与饿汉式不同的是,懒汉式并没有在类被加载的时候去创建对象,而是将类对象的创建交给了一个暴露的方法。当第一次使用这个方法的时候,instance是空的,那么它就会先创建出一个对象,那么接下来的调用都只需要直接返回这个对象。

对于01方法来说,线程是不安全的,为什么这么说呢?在多线程的情况下,可能会出现多个线程同时进到if判断中,并且都是第一次进到这个判断,那么就会创建出多个对象,违背了单例模式的设计思想。

对于02方法来说,线程是安全,但是对一个方法上锁,在高并发的情况下,每个线程使用这个方法都需要获取锁,导致系统的性能大大降低。

03方法又叫双重检查,是推荐使用的。只有在对象未被创建的情况下,才会出现线程安全的问题。那么,对需要创建对象的线程,先让它进到第一重判断中,然后通过同步代码块,只让其中的一个线程获取到锁,并且new出对象,这个线程结束之后,其他线程获取到锁进入第二重判断,由于第一个线程已经创建好了对象,那么到它就不会再创建了。

3.静态内部类创建对象

public class Singleton{
  private Singleton(){
    
  }
  private static class HolderClass{
    private final static Singleton instance = new Singleton();
    public static Singleton getInstance(){
      return HolderClass.instance;
    }
  }
}

Singleton的对象是作为内部类的成员变量,当Singleton类加载时,不会发生实例化,只有当第一次调用内部类的getInstance方法的时候,内部类才会被加载,对象才会被一同创建。

静态内部类比上面两种方式好在哪些地方呢?

对象只有在第一次使用内部类的方法的时侯才会创建,且只会创建一次。那饿汉式也一样啊,有什么区别?饿汉式下,因为对象属性作为类的成员变量,当类加载的时候就会直接创建出来,可能会无意识的创建出来。而对于静态内部类来说,将想要创建的对象和它所属的类(外部类)分开了,放到一个内部类中,外部类的加载不会影响对象。

类的静态属性只会在类第一次加载的时候会被初始化,在类进行初始化的时候,别的线程是无法进入的,保障了线程安全问题。而得到对象的方法没有加锁的限制,不会影响性能。

综上:静态内部类的方法实现了延迟加载,保障线程安全的前提下,又不会影响性能。

三、优缺点
优点:提供了对唯一实例的受控访问,节约系统资源,允许可变数目的实例。

缺点:没有抽象层,扩展较困难;职责过重,一定程度上违背了单一职责原则,因为它既提供了创建对象的方法,又提供了业务方法;Java的垃圾回收技术,将会导致共享的单例对象状态丢失,需要重新创建对象。

四、适用场景
系统只需要一个实例对象;客户调用类的单个实例只允许使用一个公共访问点

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值