【JUC并发】单例模式正确姿势汇总:普通饿汉式,枚举饿汉式,普通懒汉式,DCL懒汉式,静态内部类懒汉式

解析每种实现的线程安全,以及单例模式相关面试题的解答。给出破坏单例模式的方法及解决办法

介绍

单例模式有以下特点:
  1、单例类只能有一个实例。(构造器私有)
  2、单例类必须自己创建自己的唯一实例。(懒汉式懒加载,饿汉式直接创建)
  3、单例类必须给所有其他对象提供这一实例。(getInstance())

实现

普通饿汉式

//1.为什么加final?===防止子类继承从而重写方法改写单例
final class SingleDemo1 {
    //2.这样初始化是否能保证单例对象创建时的线程安全?===可以,由类加载器保障
    private static final SingleDemo1 INSTANCE=new SingleDemo1();
    //3.为什么设置为私有?是否能防止反射创建新的实例?===防止外部调用构造器创建多个实例。不能防止反射创建新实例。
    private SingleDemo1(){}
    //4.为什么提供静态方法而不是直接将 INSTANCE 设置为 public, 说出你知道的理由===提供更好的封装性,可以在方法内部实现一些懒惰的初始化逻辑。
    public static SingleDemo1 getInstance(){
        return INSTANCE;
    }
}

枚举饿汉式(推荐)

//1.枚举单例是如何限制实例个数的?===按照声明的个数在类加载时实例化对象
//2.枚举单例在创建时是否有并发问题?===没有,由类加载器保障安全性
//3.枚举单例能否被反射破坏单例?===不能
//4.枚举单例能否被反序列化破坏单例?===不能
//5.枚举单例属于懒汉式还是饿汉式?===饿汉
//6.枚举单例如果希望加入一些单例创建时的初始化逻辑该如何做?===写构造方法
final class SingleEnum{
    private SingleEnum(){}
    public static final SingleEnum getInstance(){
        return SingleEnumDemo.INSTANCE.getInstance();
    }
    private enum SingleEnumDemo{
        INSTANCE;
        private final SingleEnum singleEnum;
        SingleEnumDemo(){
            singleEnum=new SingleEnum();
        }
        public final SingleEnum getInstance(){
            return singleEnum;
        }
    }
}

普通懒汉式

final class SingleDemo3{
    private static SingleDemo3 INSTANCE=null;
    private SingleDemo3(){}
    //1.分析这里的线程安全, 并说明有什么缺点?===线程安全,同步代码块范围过大,性能较差
    public static synchronized SingleDemo3 getInstance(){
        if (INSTANCE==null){
            INSTANCE=new SingleDemo3();
        }
        return INSTANCE;
    }
}

DCL懒汉式

final class SingleDemo4{
    //1.解释为什么要加 volatile ?===防止指令重排导致异常
    private static volatile SingleDemo4 INSTANCE=null;
    private SingleDemo4(){

    }
    //2.对比实现3:SingleDemo3, 说出这样做的意义?=== 缩小同步范围,提高性能
    public static SingleDemo4 getInstance(){
        if (INSTANCE!=null){
            return INSTANCE;
        }
        synchronized (SingleDemo4.class){
            //3.为什么还要在这里加为空判断, 之前不是判断过了吗?===可能存在多个线程进入为空逻辑
            if (INSTANCE==null){
                INSTANCE=new SingleDemo4();
            }
            return INSTANCE;
        }
    }
}

静态内部类懒汉式

final class SingleDemo5{
    private SingleDemo5(){}
    //1.在创建时是否有并发问题?===没有,有类加载器保障
    public static SingleDemo5 getInstance(){
        return SingleStatic.INSTANCE;
    }
    //2.属于懒汉式还是饿汉式?===懒汉式,只有调用时才会初始化静态内部类
    static class SingleStatic{
        private static final SingleDemo5 INSTANCE=new SingleDemo5();
    }
}

破坏与防止

反射

//SingleDemo1 防止反射破坏
private SingleDemo1(){
	if (INSTANCE!=null){
   		 throw new RuntimeException("请通过 getInstance()方法获取");
    }
}

序列化

重写反序列化方法readResolve(), 反序列化时直接返回相关单例对象

public Object readResolve(){
        return INSTANCE;
    }
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

愿你满腹经纶

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值