单例模式

137 阅读2分钟

定义

单例模式(Singleton Pattern)是 Java 中最简单的设计模式之一。这种类型的设计模式属于创建型模式,它提供了一种创建对象的最佳方式。

这种模式涉及到一个单一的类,该类负责创建自己的对象,同时确保只有单个对象被创建。这个类提供了一种访问其唯一的对象的方式,可以直接访问,不需要实例化该类的对象。

建议使用第 3 种饿汉方式。只有在要明确实现 lazy loading 效果时,才会使用静态内部类。如果涉及到反序列化创建对象时,可以尝试使用枚举方式。如果有其他特殊的需求,可以考虑使用双检锁方式

1. 饿汉式

不管用不用我先创建出来,线程安全但占用内存

public class SingleTest {
    private static SingleTest singleTest=new SingleTest();
    private SingleTest(){};
    public static SingleTest getInstance(){
        
        return singleTest;
    }
}

2. 懒汉式

用的时候再加载,但线程不安全

public class SingleTest {
    private static SingleTest singleTest;
    private SingleTest(){};
    public static SingleTest getInstance(){
        if (singleTest==null)
            singleTest=new SingleTest();
        return singleTest;
    }
}

3. 懒汉式,线程安全

双重检测并加锁

public class SingleTest {
    private static  volatile SingleTest singleTest;
    private SingleTest(){};
    public static SingleTest getInstance(){
        // 线程A和线程B判断是否存在
        if (singleTest==null){
            // 线程A先拿到锁,线程B阻塞
            synchronized (SingleTest.class){
                 //线程A创建对象并赋值,归还锁,线程B进入判断不为null结束。
                if (singleTest==null)
                // 由于new 不是一个原子性操作,会由指令重排导致一些问题,因此我们在该属性上加上volatile
                // 一个对象的创建包括分配空间- 初始化对象- 对象指向空间
                // 问题: 线程A创建对象,执行了分配空间,对象指向空间
                // 线程B进入拿到对象,返回引用,此时对象其实并没有初始化
                singleTest=new SingleTest();
            }

        }
        return singleTest;
    }
}

4. 静态内部类实现

SingleTest 类被装载了,singleTest 不一定被初始化。因为 SingleHolder 类没有被主动使用,只有通过显式调用 getInstance 方法时,才会显式装载 SingletHolder 类,从而实例化 singleTest。 线程安全。

public class SingleTest {
    private SingleTest(){};
    public static SingleTest getInstance(){
        return SingleHolder.singleTest;
    }
    public static final class SingleHolder{
        private static final SingleTest singleTest=new SingleTest();
    }
}

5. 枚举实现-实现单例模式的最佳方法

之前的方式都可以被反射所破坏,而enum保证了这个

public enum  EnumTest {
    Instance;
    public EnumTest getInstance(){
        return EnumTest.Instance;
    }
}