单例模式

单例模式概述

单例模式的定义:确保一个类只有一个实例,并提供一个全局访问点来访问这个唯一实例。

单例模式的要点

  • 某个类只能有一个实例。
  • 必须自行创建这个实例。
  • 必须自行向整个系统提供这个实例。

单例模式动机

如何保证一个类只有一个实例并且这个实例易于被访问?

  • 全局变量:可以确保对象随时都可以被访问,但不能防止创建多个对象。
  • 让类自身负责创建和保存它的唯一实例,并保证不能创建其他实例,它还提供一个访问该实例的方法。

单例模式的结构与实现

单例模式的结构

单例模式只包含一个单例角色:Singleton(单例)
  • 对于 Singleton(单例),在单例类的内部创建它的唯一实例,并通过静态方法 getInstance()让客户端可以使用它的唯一实例;
  • 为了防止在外部对单例类实例化,将其构造函数的可见性设为private;
  • 在单例类内部定义了一个 Singleton 类型的静态对象作为供外部共享访问的唯一实例。

典型的单例模式的代码:

public class Singleton {
private static Singleton instance=null; //静态私有成员变量
//私有构造函数,无法通过new来实例化
private Singleton() {
}
//静态公有工厂方法,返回唯一实例
public static Singleton getInstance() {
if(instance==null)
instance=new Singleton();
return instance;
}
}

饿汉式单例与懒汉式单例

饿汉式单例类(Eager Singleton)

从图中可以看出,由于在定义静态变量的时候就已经实例化了单例类,因此在类加载时单例对象就已经创建完成了。当类被加载时,静态变量instance会被初始化,此时类的私有构造函数会被调用,单例的唯一实例将被创建。

懒汉式单例类(Lazy Singleton)

从图中可以看出,懒汉式单例在第一次调用getInstance( )方法时实例化,在类加载时并不自行实例化,这种技术又称为延迟加载(Lazy Load)技术,即需要的时候再加载实例。

懒汉式单例类与双重检查锁定

懒汉式单例类因为不会在加载时直接将唯一的单例实例化,多个线程同时访问将会导致创建多个实例对象,因此,需要处理好多个线程同时访问的问题。在这里,我们引入Double-Check Locking双重检查锁定来处理这个问题。

使用上述的锁技术后,我们假设某一瞬间A和B两个线程同时调用了getInstance( )这个方法,此时的instance对象的值为null,A和B均可以通过第一重锁instance == null的判断。此时线程A会进入synchronized锁定的代码中执行实例创建代码,而线程B将会处于排队等待状态,必须等待A执行完毕之后才可以进入synchronized锁定的代码。当A执行完毕之后线程B并不知道实例已经被创建,若其继续创建实例将会导致产生多个单例对象,此时就需要第二重锁,其中的instance == null的判断显然已经为false,线程B知晓此时已经产生了单例类,跳过创建实例的语句,继续向后进行执行。

需要注意的是,使用双重检测锁定时应该在静态成员变量instance之前增加一个修饰符volatile,被volatile修饰的成员变量可以保证多个线程都能够正确处理。

饿汉式单例类与懒汉式单例类的比较

  • 饿汉式单例类:无须考虑多个线程同时访问的问题;调用速度和反应时间优于懒汉式单例;资源利用效率不及懒汉式单例;系统加载时间可能会比较长。
  • 懒汉式单例类:实现了延迟加载;必须处理好多个线程同时访问的问题;需通过双重检查锁定等机制进行控制,将导致系统性能受到一定影响。

单例模式的优缺点与适用环境

模式优点

  • 提供了对唯一实例的受控访问。
  • 可以节约系统资源,提高系统的性能。
  • 允许可变数目的实例(多例类)。

模式缺点

  • 扩展困难(缺少抽象层)。
  • 单例类的职责过重。
  • 由于自动垃圾回收机制,可能会导致共享的单例对象的状态丢失。

模式适用环境

  • 系统只需要一个实例对象,或者因为资源消耗太大而只允许创建一个对象。
  • 客户调用类的单个实例只允许使用一个公共访问点,除了该公共访问点,不能通过其他途径访问该实例。

发表回复

Breeze Wang

A student majoring in Software Engineering at Central South University has an understanding of software development techniques, software architecture, and is able to use Godot to develop game projects. I am currently in the Game Development Laboratory at Central South University. I have experience participating in Global Game Jam. Loving game development.