java单例五种实现模式解析

  

Java单例五种实现模式解析

什么是单例模式?

单例模式是指一个类只能被实例化一次,并且全局都可以访问到这个实例。在实际开发中,很多情况下我们只需要一个实例,例如全局配置信息、日志管理等等,这时候使用单例模式可以节省系统资源,减少不必要的开销。

单例模式的特点

  • 保证一个类只有一个实例。
  • 提供一个访问该实例的全局入口。
  • 不能被其他对象实例化。

五种实现模式

1. 饿汉式

线程安全

饿汉式在类被加载的同时就创建好了唯一的实例,故天然的线程安全。

public class Singleton {
    private static final Singleton instance = new Singleton();
    private Singleton(){}
    public static Singleton getInstance(){ 
        return instance;
    }
}

示例说明

public static void main(String[] args) {
    Singleton instance1 = Singleton.getInstance();
    Singleton instance2 = Singleton.getInstance();
    System.out.println(instance1 == instance2);
}

输出结果为 true,表明两个实例指向同一内存空间,即单例模式被实现。

2. 懒汉式

线程不安全

懒汉式在第一次使用的时候才创建实例,需要考虑线程安全性问题,否则会出现多个实例的情况。

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

线程安全

使用双重判定锁的方式可以保证线程安全性。

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

示例说明

public static void main(String[] args) {
    Singleton instance1 = Singleton.getInstance();
    Singleton instance2 = Singleton.getInstance();
    System.out.println(instance1 == instance2);
}

输出结果为 true,表明两个实例指向同一内存空间,即单例模式被实现。

3. 静态内部类

这种方式利用了 Classloader 的机制来保证初始化实例时只有一个线程。静态内部类不会在类加载时就初始化,而是当被调用时才进行初始化。

public class Singleton {
    private Singleton(){}
    private static class SingletonHolder{
        private static final Singleton instance = new Singleton();
    }
    public static final Singleton getInstance(){
        return SingletonHolder.instance;
    }
}

示例说明

public static void main(String[] args) {
    Singleton instance1 = Singleton.getInstance();
    Singleton instance2 = Singleton.getInstance();
    System.out.println(instance1 == instance2);
}

输出结果为 true,表明两个实例指向同一内存空间,即单例模式被实现。

4. 枚举类型

枚举类型被限制了元素个数,保证了单例模式的实现,且避免了线程安全问题。

public enum Singleton {
    INSTANCE;
    public void whateverMethod() { }
}

示例说明

public static void main(String[] args) {
    Singleton instance1 = Singleton.INSTANCE;
    Singleton instance2 = Singleton.INSTANCE;
    System.out.println(instance1 == instance2);
}

输出结果为 true,表明两个实例指向同一内存空间,即单例模式被实现。

5. 双重校验锁

这种方式可以在保证线程安全的情况下实现懒加载。

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

示例说明

public static void main(String[] args) {
    Singleton instance1 = Singleton.getInstance();
    Singleton instance2 = Singleton.getInstance();
    System.out.println(instance1 == instance2);
}

输出结果为 true,表明两个实例指向同一内存空间,即单例模式被实现。

总结

以上五种单例实现方式各有优缺点,应根据具体情况选择。选用不合适的单例实现方式会导致系统资源浪费、性能降低及线程安全问题等。

相关文章