设计模式-单例模式

By | 2022年3月16日

在Java中常见的设计模式可以分为3类,创建型模式、结构型模式和行为型模式。

而今天要说的单例模式则属于创建性模式

创建型模式

使用创建设计模式,您可以针对特定问题以最佳方式实例化对象。 对象创建过程可能导致设计问题中出现不必要的复杂性。 这就是创建设计模式通过以不同方式控制对象创建过程来提供解决方案的地方。 有五种不同的创建设计模式:


单例模式通过限制类的实例化来确保只存在一个类的实例。 它是 Java 中最简单的设计模式之一。 虽然它是最简单的设计模式,但它有很多实现问题。

让我们了解单例设计模式的原则、用法、最佳实践以及不同的实现方式。

构建类时的初始化(Singleton Eager Initialization

public class SingletonEager {
private static volatile SingletonEager instance = new SingletonEager ();



  // private constructor

  private SingletonEager() {

  }



  public static SingletonEager getInstance() {

    return instance;

  }

}

这种情况,无论是否调用这个都会创建一个示例,其预先实例化好对象,适用于高频调用的情况。

静态代码初始化(Static Block Initialization

静态块在类加载期间在调用构造函数之前执行。 它与 Eager Initialization 类似,不同之处在于类是在静态块中创建的,它为异常处理提供了一个选项。

public class SingletonStaticBlock {
	private static final SingletonStaticBlock INSTANCE;

	static {

		try {

			INSTANCE = new SingletonStaticBlock ();

		} catch (Exception e) {

			throw new RuntimeException(“It wasn’t the way expected!”, e);

		}

	}

	public static SingletonStaticBlock getInstance() {

		return INSTANCE;

	}

	private SingletonStaticBlock() {

	// …

	}

}

这种初始化方式的缺点是,如果在几个静态字段中只需要两个或三个静态字段,不管是否需要,我们都需要创建一个实例。

延时初始化(Lazy Initialization

延迟初始化在全局访问方法中创建一个实例。 通过延迟初始化,您实际上可以延迟对象的创建,直到需要它为止。

public final class SingletonLazy {
	private static volatile SingletonLazy instance = null;

	// private constructor

	private SingletonLazy() {

	}
	public static SingletonLazy getInstance() {

		if (instance == null) {

		synchronized (SingletonLazy.class) {

			instance = new SingletonLazy();

		}

	}

	return instance;

	}

}

使用此方法,您可以检查实例是否已使用实例变量创建。 如果实例为空,它将创建一个实例,否则如果实例已经创建,它将返回引用。
如果有两个线程,都将创建实例并检查实例是否为空。 现在,如果两个线程都识别出一个空实例,那么它们将通过顺序进入一个同步块来创建一个实例。 这将导致最后两个实例。 要解决此问题,您可以使用双重检查锁定方法。 它将重新检查同步块中的实例变量。

public class SingletonLazy {
	private static volatile SingletonLazy instance = null;

	// private constructor

	private SingletonLazy() {

	}
	public static SingletonLazy getInstance() {

		if (instance == null) {

			synchronized (SingletonLazy.class) {

			// Double check
			if (instance == null) {

				instance = new SingletonLazy();

			}

		}

	}

	return instance;

	}

}

Bill Pugh 单例

Bill Pugh 设计了一种使用内部静态辅助类创建单例类的方法。 由于 Java 内存模型的问题,如果有多个线程,那么每个线程都会同时创建实例。 这就是 Bill Pugh Singleton 方法起作用的地方。

public class SingletonByBillPugh {
	private SingletonByBillPugh() {

	}
	private static class LazyHolder {

		private static final SingletonByBillPugh INSTANCE = new

	SingletonByBillPugh();

	}
	public static SingletonByBillPugh getInstance() {

		return LazyHolder.INSTANCE;

	}

}

通过枚举实现单例(Singleton Using Enum)

这种单例模式由 Joshua Bloch 建议使用 Enum,因为它的值在 Java 中只实例化一次。 使用 Enum,只能保证一个实例。 它为线程安全提供了隐式支持,并且是一种以最少的努力获得单例的好方法。

public enum SingletonEnum {
	INSTANCE;

	public void someMethod(String param) {

	// some class member

	}

}