23种设计模式-单例模式

58 阅读2分钟

Java单例模式是一种常见的设计模式,它可以确保一个类只有一个实例,并提供全局访问点。在Java中,单例模式通常用于管理全局资源,例如数据库连接池、日志记录器等。

1.饿汉式实现方法

public class Singleton {
    private static Singleton instance = new Singleton();

    private Singleton() {
        // 私有构造函数
    }

    public static Singleton getInstance() {
        return instance;
    }
}

在这个实现方法中,Singleton类在类加载时就创建了一个静态实例,并在getInstance方法中返回该实例。由于静态实例是在类加载时创建的,因此它是线程安全的。

2.懒汉式实现方法

public class Singleton {
    private static Singleton instance;

    private Singleton() {
        // 私有构造函数
    }

  public static synchronized Singleton getInstance() 
  { if (instance == null) 
  { instance = new Singleton(); } return instance; }
}

在这个实现方法中,Singleton类在第一次调用getInstance方法时才创建实例。由于在多线程环境下可能会出现竞态条件,因此需要在getInstance方法中加锁或使用双重检查锁定来确保线程安全。

DCL实现单例模式

public class Singleton {
    private volatile static Singleton instance;
    
    private Singleton() {}
    
    public static Singleton getInstance() {
        if (instance == null) {
            synchronized (Singleton.class) {
                if (instance == null) {
                    instance = new Singleton();
                }
            }
        }
        return instance;
    }
}

在上面的代码中,使用了volatile关键字来确保instance的可见性,同时也保证了instance的初始化顺序。

使用DCL可以在保证线程安全的同时,避免了每次获取实例都需要加锁的开销。不过需要注意的是,在早期版本的JDK中,DCL可能存在重排序问题,导致获取到未完全初始化的实例,所以需要在使用DCL时,注意JDK的版本和实现细节。

3.枚举实现单例模式

public enum Singleton {
    INSTANCE;
    
    public void doSomething() {
        // 单例操作
    }
}

使用枚举(Enum)实现单例模式是一种简洁、安全、且易于理解的方式,因为枚举类的实例化是线程安全的,而且在Java中,枚举是天然的单例模式。

4.内部类实现单例模式

public class Singleton {
    //私有化构造函数,防止外部直接实例化
    private Singleton() {}

    //内部静态类,用于延迟加载单例对象
    private static class SingletonHolder {
        private static final Singleton instance = new Singleton();
    }

    //提供公共静态方法,返回单例对象
    public static Singleton getInstance() {
        return SingletonHolder.instance;
    }
}

在上述代码中,Singleton类的构造函数是私有的,这意味着只能在类的内部实例化对象。SingletonHolder是一个私有的静态内部类,它持有一个Singleton实例,并在内部静态变量中进行初始化。getInstance()方法返回SingletonHolder中的Singleton实例,从而保证了单例模式的正确性。由于静态内部类只会在需要时才会被加载,因此这种方式实现了延迟加载的效果,也避免了多线程下的同步问题。