线程安全下的单例模式

关键字:后端开发,设计模式,Java。

单线程的单例

私有构造方法
持有自己类的静态私有属性
获取自己类实例的静态方法
多线程场景下是不安全的
在这里插入图片描述

多线程下线程安全的单例

私有构造方法
持有自己类的私有属性
获取自己类实例的方法
synchronized 同步,线程安全的关键
在这里插入图片描述

绝对线程安全的单例(官方推荐使用)

私有构造方法,枚举默认其实就是私有的
获取自己类实例的静态方法
内部枚举类
在这里插入图片描述

单例模式有多种实现方式,但是,有三个相同的特点:

构造器私有,防止外部new对象
含持有自己类型的属性;
对外提供获取实例的静态方法;

使用场景:

工具类,比如获取所有城市的工具方法;
创建对象需要消耗资源的类

拓展知识

通过反射技术可以破坏除枚举单例以外的其他单例模式。
在这里插入图片描述
控制台结果输出为:
在这里插入图片描述

枚举类绝对线程安全的原因分析:

枚举类型的最终反编译源码:

public final class T extends Enum
{
    
    
    private T(String s, int i)
    {
    
    
        super(s, i);
    }
    public static T[] values()
    {
    
    
        T at[];
        int i;
        T at1[];
        System.arraycopy(at = ENUM$VALUES, 0, at1 = new T[i = at.length], 0, i);
        return at1;
    }

    public static T valueOf(String s)
    {
    
    
        return (T)Enum.valueOf(demo/T, s);
    }

    public static final T SPRING;
    public static final T SUMMER;
    public static final T AUTUMN;
    public static final T WINTER;
    private static final T ENUM$VALUES[];
    static
    {
    
    
        SPRING = new T("SPRING", 0);
        SUMMER = new T("SUMMER", 1);
        AUTUMN = new T("AUTUMN", 2);
        WINTER = new T("WINTER", 3);
        ENUM$VALUES = (new T[] {
    
    
            SPRING, SUMMER, AUTUMN, WINTER
        });
    }
}

通过反编译后代码我们可以看到,public final class T extends Enum,说明,该类是继承了Enum类的,同时final关键字告诉我们,这个类也是不能被继承的。当我们使用enmu来定义一个枚举类型的时候,编译器会自动帮我们创建一个final类型的类继承Enum类,所以枚举类型不能被继承,我们看到这个类中有几个属性和方法。

而且所有的成员变量和成员方法都是static类型的,因为static类型的属性会在类被加载之后被初始化,当一个Java类第一次被真正使用到的时候静态资源被初始化、Java类的加载和初始化过程都是线程安全的。所以,创建一个enum类型是线程安全的。

猜你喜欢

转载自blog.csdn.net/weixin_46011971/article/details/107051057