前言
整個系統中只會出現要給實例,比如Spring中的Bean基本都是單例的
UML類圖
無
代碼示例
package com.sw.learn.pattern.B_create.c_singleton;public class Main {public static void main(String[] args) {// double check locking 線程安全+懶加載 ??
// SingletonDCL instance = SingletonDCL.getInstance();// 靜態內部類 線程安全+懶加載 ????
// Singleton s1 = Singleton.getInstance();
// Singleton s2 = Singleton.getInstance();
// System.out.println(s1 == s2); // true// 枚舉類 線程安全+餓漢式 ??????
// SingletonEnum.INSTANCE.doSomething();// 基于枚舉內部類的懶漢式單例模式 ????????BeanContainer instance2 = BeanContainer.getInstance();BeanContainer instance3 = BeanContainer.getInstance();System.out.println(instance2 == instance3); // true}
}class Singleton {// 私有構造方法,防止外部實例化private Singleton() {System.out.println("Singleton constructor called.");}// 靜態內部類,只有在第一次調用 getInstance() 時才會加載private static class Holder {private static final Singleton INSTANCE = new Singleton();}// 對外提供獲取實例的方法public static Singleton getInstance() {return Holder.INSTANCE;}
}class SingletonDCL {// 使用 volatile 防止初始化時指令重排序,確保線程安全private static volatile SingletonDCL instance;private SingletonDCL() {System.out.println("SingletonDCL constructor called.");}public static SingletonDCL getInstance() {if (instance == null) { // 第一次檢查(不加鎖) 提高性能synchronized (SingletonDCL.class) {if (instance == null) { // 第二次檢查(加鎖后再檢查) 防止多個線程同時通過第一層檢查后并發創建;instance = new SingletonDCL();}}}return instance;}
}enum SingletonEnum {INSTANCE;public void doSomething() {System.out.println("Doing something with enum singleton.");}
}// 枚舉編譯后效果
//final class SingletonEnum2 extends Enum<SingletonEnum2> {
// public static final SingletonEnum2 INSTANCE = new SingletonEnum2("INSTANCE", 0);
//
// private SingletonEnum2(String name, int ordinal) {
// super(name, ordinal);
// }
//}class BeanContainer {// 調用getInstance方法時,第一次初始化ContainerHolder枚舉類,初始的時候執行構造方法,實例化BeanContainer對象/*** 第一步:調用 ContainerHolder.HOLDER* JVM 首次訪問 ContainerHolder 時會觸發類加載。* <p>* 內部類不會在外部類加載時加載,只有在首次訪問時才加載(這就是懶加載)。* <p>* 枚舉類加載也是線程安全的,JVM 會保證枚舉類只加載一次,不會有并發初始化問題。** @return*/public static BeanContainer getInstance() {return ContainerHolder.HOLDER.instance;}private enum ContainerHolder {HOLDER; // 容器,裝載了BeanContainer對象/*** 第二步:加載 enum ContainerHolder* 枚舉類 ContainerHolder 加載時,會創建一個 enum 常量 HOLDER。*/private BeanContainer instance;ContainerHolder() {instance = new BeanContainer(); // 會被執行一次,初始化 instance, 即 ContainerHolder.HOLDER 被加載時。}}
}