Java设计模式---单例模式


一、概述

单例模式的定义就是整个程序有且仅有一个实例。该类负责创建自己的对象,同时确保只有一个对象被创建。属于设计模式三大类中的创建型模式

特点

  • 单例类只有一个实例对象
  • 该单例对象必须由单例类自行创建
  • 单例类对外提供一个访问该单例的全局访问点

UML图

二、常见实现方式

常见的单例模式实现方式有五种:饿汉式懒汉式双重锁懒汉式静态内部类式枚举单例。下面将列举这几种方式的代码实现。

1.饿汉式

public class SingletonDemo1 {

    //线程安全的
    //类初始化时,立即加载这个对象
    //调用效率高。但是不能延时加载
    private static SingletonDemo1 instance = new SingletonDemo1();

    private SingletonDemo1() {
    }

    //方法没有加同步块,所以它效率高
    public static SingletonDemo1 getInstance() {
        return instance;
    }
}

由于该模式在加载类的时候对象就已经创建了,所以加载类的速度比较慢,但是获取对象的速度比较快,且是线程安全的。

2.懒汉式

public class SingletonDemo2 {

    //线程不安全的

    private static SingletonDemo2 instance = null;

    private SingletonDemo2() {
    }

    //运行时加载对象
    public static SingletonDemo2 getInstance() {
        if (instance == null) {
            instance = new SingletonDemo2();
        }
        return instance;
    }
}

由于该模式是在运行时加载对象的,所以加载类比较快,但是对象的获取速度相对较慢,且线程不安全如果想要线程安全的话可以加上synchronized关键字,但是这样会付出惨重的效率代价。3.

3.双重锁懒汉式(Double Check Lock)

public class Singleton {  
    private volatile static Singleton singleton;  
    private Singleton (){}  
    public static Singleton getSingleton() {  
    if (singleton == null) {  
        synchronized (Singleton.class) {  
        if (singleton == null) {  
            singleton = new Singleton();  
        }  
      }  
    }  
    return singleton;  
  }  
}

双重检查模式,进行了两次的判断,第一次是为了避免不要的实例,第二次是为了进行同步,避免多线程问题。由于singleton = new Singleton()对象的创建在JVM中可能会进行重排序,在多线程访问下存在风险,使用volatile修饰signleton实例变量有效,解决该问题。

4.静态内部类式

public class Singleton{
  private Singleton(){}

  private static class SingletonHoler{
     private static Singleton INSTANCE = new Singleton();
  }

  public static Singleton getInstance(){
    return SingletonHoler.INSTANCE;
  }
}

外部类加载时并不需要立即加载内部类,内部类不被加载则不去初始化INSTANCE,故而不占内存。即当SingleTon第一次被加载时,并不需要去加载SingleTonHoler,只有当getInstance()方法第一次被调用时,才会去初始化INSTANCE,第一次调用getInstance()方法会导致虚拟机加载SingleTonHoler类,这种方法不仅能确保线程安全,也能保证单例的唯一性,同时也延迟了单例的实例化。

5.枚举单例(推荐使用)

public enum EnumSingle {

    INSTANCE;

    public EnumSingle getInstance(){
        return INSTANCE;
    }
}

该方式简单可自由序列化;保证只有一个实例(即使使用反射机制也无法多次实例化一个枚举量);线程安全。唯一的缺点是非懒加载方式。

三、优缺点

优点

  • 提供了对唯一实例的受控访问。
  • 由于在系统内存中只存在一个对象,因此可以节约系统资源,对于一些需要频繁创建和销毁的对象单例模式无疑可以提高系统的性能。
  • 允许可变数目的实例。

缺点

  • 由于单利模式中没有抽象层,因此单例类的扩展有很大的困难。
  • 单例类的职责过重,在一定程度上违背了“单一职责原则”。
  • 滥用单例将带来一些负面问题,如为了节省资源将数据库连接池对象设计为的单例类,可能会导致共享连接池对象的程序过多而出现连接池溢出;如果实例化的对象长时间不被利用,系统会认为是垃圾而被回收,这将导致对象状态的丢失。

四、使用

Spring中创建的Bean实例默认都是单例模式存在的。


文章作者: nfLJ
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 nfLJ !
评论
 上一篇
Java集合框架---ArrayList Java集合框架---ArrayList
简介 ArrayList 的底层是数组队列,相当于动态数组。与 Java 中的数组相比,它的容量能动态增长。在添加大量元素前,应用程序可以使用ensureCapacity操作来增加 ArrayList 实例的容量。这可以减少递增式再分配的数
2020-07-07
下一篇 
设计模式概述 设计模式概述
设计模式有两种分类方法,即根据模式的目的来分和根据模式的作用的范围来分。 根据目的来分根据模式是用来完成什么工作来划分,这种方式可分为创建型模式、结构型模式和行为型模式 3 种。 创建型模式:用于描述“怎样创建对象”,它的主要特点是“将对
2020-07-06
  目录