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

image.png

1 饿汉式 hungry loading

类加载到内存后就实例化一个单例,JVM保证线程安全;唯一缺点是不管是否用到类转载时就完成实例化。

  1. public class T01_Hungry {
  2. private static final T01_Hungry INSTANCE = new T01_Hungry();
  3. private T01_Hungry() {
  4. }
  5. public static T01_Hungry getInstance() {
  6. return INSTANCE;
  7. }
  8. }

2 懒汉式 lazy loading

使用时才初始化,但存在线程不安全问题。

  1. /**
  2. * 单例模式——懒汉式
  3. *
  4. * 问题:线程不安全
  5. */
  6. public class T02_Lazy {
  7. private static T02_Lazy instance;
  8. private T02_Lazy() {
  9. }
  10. public static T02_Lazy getInstance() {
  11. if (instance == null) {
  12. instance = new T02_Lazy();
  13. }
  14. return instance;
  15. }
  16. }

3 懒汉式改进1:getInstance方法加synchronize进行同步

通过synchronized关键字来解决线程不安全问题,但是效率会降低。

  1. /**
  2. * 懒汉式改-进加: getInstance方法加synchronize进行同步
  3. *
  4. * 问题:整个方法加锁,锁太粗,效率偏低
  5. */
  6. public class T03_LazyWithSynchronize {
  7. private static T03_LazyWithSynchronize instance;
  8. private T03_LazyWithSynchronize() {
  9. }
  10. public static synchronized T03_LazyWithSynchronize getInstance() {
  11. if (instance == null) {
  12. instance = new T03_LazyWithSynchronize();
  13. }
  14. return instance;
  15. }
  16. }

4 懒汉式改进2:双重检查 DCL

  1. /**
  2. * 懒汉式改 - 双重检查
  3. */
  4. public class T04_LazyWithdoubleCheck {
  5. // volatile 语义:保证指令不乱序执行,高并发下避免获取到半加载的实例
  6. private static volatile T04_LazyWithdoubleCheck instance;
  7. private T04_LazyWithdoubleCheck() {
  8. }
  9. public static T04_LazyWithdoubleCheck getInstance() {
  10. if (instance == null) {
  11. synchronized (T04_LazyWithdoubleCheck.class) {
  12. if (instance == null) {
  13. instance = new T04_LazyWithdoubleCheck();
  14. }
  15. }
  16. }
  17. return instance;
  18. }
  19. }

5 静态内部类方式

JVM保证单例,加载外部类是不会加载内部类,可以实现懒加载

  1. /**
  2. * 单例模式-静态内部类
  3. */
  4. public class T05_StaticInnerClass {
  5. private T05_StaticInnerClass() {
  6. }
  7. private static class Inner {
  8. private static final T05_StaticInnerClass INSTANCE = new T05_StaticInnerClass();
  9. }
  10. public static T05_StaticInnerClass getInstance() {
  11. return Inner.INSTANCE;
  12. }
  13. }

image.png

6 枚举单例

不仅可以解决线程同步问题,还可以防止反序列化。

  1. /**
  2. * 单例模式 - 枚举实现
  3. *
  4. */
  5. public enum T06_Enum {
  6. /**
  7. * 单例
  8. */
  9. INSTANCE;
  10. }