意图

保证一个类仅有一个实例,并提供一个全局访问结点。

适用性

  1. 类只能有一个实例,客户可以从一个众所周知的结点访问它。
  2. 当这个唯一实例通过子类化可扩展的,客户无需更改代码就能使用一个扩展的实例。

效果

  1. 对唯一实例的受控访问——单例类封装其唯一实例,所以可以控制客户何时及怎样访问它。
  2. 缩小名字空间——单例模式是一种对全局变量的改进.
  3. 允许对操作和表示的精化——Singleton类可以有子类,允许在运行时配置应用。
  4. 允许可变数目的实例——可以用相同的方法控制实例的数目。
  5. 比类操作更灵活

实现方式

饿汉式

  1. /**
  2. * 饿汉式实现单例模式
  3. *
  4. * @author Jinhua
  5. * @date 2020/8/22 22:47
  6. */
  7. public class SingletonHungry implements MySingleton {
  8. /**
  9. * 类加载准备阶段的时候就进行初始化
  10. */
  11. private static final SingletonHungry INSTANCE = new SingletonHungry();
  12. private SingletonHungry() {
  13. }
  14. public static SingletonHungry getInstance() {
  15. return INSTANCE;
  16. }
  17. @Override
  18. public void doSomething() {
  19. System.out.println(this + "\t饿汉实现单例模式");
  20. }
  21. }

懒汉式(线程不安全)

  1. /**
  2. * 懒汉模式单例(线程不安全)
  3. *
  4. * @author Jinhua
  5. * @date 2020/8/22 22:49
  6. */
  7. public class SingletonLazy implements MySingleton {
  8. private static SingletonLazy instance = null;
  9. private SingletonLazy() {
  10. }
  11. /**
  12. * 模拟多线程下不安全的问题
  13. *
  14. * @return 返回单例对象
  15. * @throws InterruptedException 中断异常
  16. */
  17. public static SingletonLazy getInstance() throws InterruptedException {
  18. if (instance == null) {
  19. // 睡眠用于模拟线程不安全的问题
  20. Thread.sleep(5000);
  21. instance = new SingletonLazy();
  22. }
  23. return instance;
  24. }
  25. @Override
  26. public void doSomething() {
  27. System.out.println(this + "\t懒汉实现单例模式.");
  28. }
  29. }

懒汉式(线程安全)

  1. /**
  2. * 懒汉模式单例(线程安全)
  3. *
  4. * @author Jinhua
  5. * @date 2020/8/22 22:52
  6. */
  7. public class SingletonLazyThread implements MySingleton {
  8. private static SingletonLazyThread instance;
  9. private SingletonLazyThread() {
  10. }
  11. /**
  12. * 测试多线程环境下线程安全的懒汉实现单例
  13. *
  14. * @return 单例对象
  15. * @throws InterruptedException 中断异常
  16. */
  17. public static synchronized SingletonLazyThread getInstance() throws InterruptedException {
  18. if (instance == null) {
  19. // 睡眠用于模拟线程的问题
  20. Thread.sleep(5000);
  21. instance = new SingletonLazyThread();
  22. }
  23. return instance;
  24. }
  25. @Override
  26. public void doSomething() {
  27. System.out.println(this + "\t线程安全的懒汉单例模式.");
  28. }
  29. }

双重检查模式

  1. /**
  2. * 双重检查的单例模式
  3. *
  4. * @author Jinhua
  5. * @date 2020/8/22 22:39
  6. */
  7. public class SingletonDoubleCheck implements MySingleton {
  8. private static volatile SingletonDoubleCheck instance = null;
  9. private SingletonDoubleCheck() {
  10. }
  11. public static SingletonDoubleCheck getInstance() {
  12. // 避免多次进入同步判断,影响性能
  13. if (instance == null) {
  14. synchronized (SingletonDoubleCheck.class) {
  15. // 同步块中的判断,保证唯一
  16. if (instance == null) {
  17. instance = new SingletonDoubleCheck();
  18. }
  19. }
  20. }
  21. return instance;
  22. }
  23. @Override
  24. public void doSomething() {
  25. System.out.println(this + "\t双重检查单例模式");
  26. }
  27. }

枚举单例

  1. /**
  2. * 枚举实现单例
  3. *
  4. * @author Jinhua
  5. * @date 2020/8/22 23:03
  6. */
  7. public enum SingletonEnum implements MySingleton {
  8. /**
  9. * 单例的枚举
  10. */
  11. INSTANCE;
  12. private Object readResolve() throws ObjectStreamException {
  13. return INSTANCE;
  14. }
  15. @Override
  16. public void doSomething() {
  17. System.out.println(this + "\t枚举单例模式.");
  18. }
  19. public static MySingleton getInstance() {
  20. return SingletonEnum.INSTANCE;
  21. }
  22. }

静态内部类单例

  1. /**
  2. * 静态内部实现类单例模式
  3. *
  4. * @author Jinhua
  5. * @date 2020/8/22 23:02
  6. */
  7. public class SingletonStaticInnerClass implements MySingleton {
  8. private SingletonStaticInnerClass() {
  9. }
  10. public static SingletonStaticInnerClass getInstance() {
  11. return SingletonHolder.S_INSTANCE;
  12. }
  13. @Override
  14. public void doSomething() {
  15. System.out.println(this + "\t静态内部类实现单例模式.");
  16. }
  17. /**
  18. * 静态内部类中引用当前对象
  19. */
  20. private static class SingletonHolder {
  21. private static final SingletonStaticInnerClass S_INSTANCE = new SingletonStaticInnerClass();
  22. }
  23. }

管理单例对象

容器管理单例对象

  1. /**
  2. * 使用容器管理单例对象
  3. *
  4. * @author Jinhua
  5. * @date 2020/8/22 23:05
  6. */
  7. public class SingletonManager {
  8. /**
  9. * 存储单例对象的 map
  10. */
  11. private static final Map<String, Object> OBJ_MAP = new HashMap<>();
  12. private SingletonManager() {
  13. }
  14. /**
  15. * 注册到 map 中的方法
  16. * @param key 注册的键
  17. * @param instance 单实例
  18. */
  19. public static void registerService(String key, Object instance) {
  20. if (!OBJ_MAP.containsKey(key)) {
  21. OBJ_MAP.put(key, instance);
  22. }
  23. }
  24. /**
  25. * 获取根据键单实例的服务
  26. * @param key 键
  27. * @return 单例
  28. */
  29. public static Object getService(String key) {
  30. return OBJ_MAP.get(key);
  31. }
  32. }