Java设计模式之单例模式

单例模式(Singleton Pattern)是 Java 中最简单的设计模式之一。这种类型的设计模式属于创建型模式,它提供了一种创建对象的最佳方式。这种模式涉及到一个单一的类,该类负责创建自己的对象,同时确保只有单个对象被创建。这个类提供了一种访问其唯一的对象的方式,可以直接访问,不需要实例化该类的对象。

单例模式用来保证一个类仅有一个实例,并提供一个访问他的全局访问点;主要解决了一个全局使用类的频繁创建与销毁;

注意事项:

  • 单例类只能有一个实例

  • 单例类必须自己创建自己唯一的实例

  • 单例类必须给所有其他对象提供这一实例

单例模式从实现方式上可以分为饿汉式单例模式和懒汉式单例模式,饿汉式单例模式是线程安全的,懒汉式单例模式需要考虑线程安全性,实现线程安全的懒汉式单例模式一般有两种实现内部类式和双重检查式;

(1)饿汉式 – 线程安全

// 饿汉式单例
public class Singleton1 {
 
    // 指向自己实例的私有静态引用,主动创建
    private static Singleton1 singleton1 = new Singleton1();
 
    // 私有的构造方法
    private Singleton1(){}
 
    // 以自己实例为返回值的静态的公有方法,静态工厂方法
    public static Singleton1 getSingleton1(){
        return singleton1;
    }
}

饿汉式线程安全的原因:

因为在类加载时就实例化了,即使多个线程同时获取它,取到的都是类加载时实例化的那个变量的值;

(2)懒汉式-线程不安全

// 懒汉式单例
public class Singleton2 {
 
    // 指向自己实例的私有静态引用
    private static Singleton2 singleton2;
 
    // 私有的构造方法
    private Singleton2(){}
 
    // 以自己实例为返回值的静态的公有方法,静态工厂方法
    public static Singleton2 getSingleton2(){
        // 被动创建,在真正需要使用时才去创建
        if (singleton2 == null) {
            singleton2 = new Singleton2();
        }
        return singleton2;
    }
}

懒汉式线程不安全的原因:

多个线程同时使用时,例如第一个线程判断完if(single==null)为空时,进入了if的代码中,还没开始new对象时,这时第二个线程可能也正好判断为空进来了if,这时就会创造出两个实例。

(3)线程安全的懒汉式-内部类方式

public class Singleton {
    //静态私有内部类
    private static class InnerClass {
        private final static Singleton instance = new Singleton();
    }
 
    private Singleton(){
 
    }
 
    public static Singleton getInstance(){
        return InnerClass.instance;
    }
}

线程安全的原因:

同样使用了类加载机制,这个会延迟加载,因为Singleton加载了,但内部类InnerClass类没有被主动调用,只有显式的调用getInstance()方法对象才会被加载;

(4)线程安全的懒汉式-双重检查方式

public class Singleton {
 
    // volatile: 防止指令重排序
    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;
    }
}

一般建议使用饿汉式方式;

参考文献:菜鸟教程|单例模式

1 Comment

  1. go for it

    回复

Leave a Reply