线程安全单例模式的问题

1.实现一:

public class Singleton implements Serializable {
    private Singleton(){}
    
    private static final Singleton INSTANCE = new Singleton();
    
    public static Singleton getInstance(){
        return  INSTANCE;
    }
    
}

1.1、为什么加final

怕子类覆盖父类里的方法

1.2、如果实现了序列化接口,还要做什么来防止反序列化破坏单例

反序列化也会生成新的对象,如果与单例模式中想要维护对象不同,就相当于破坏了单例。
解决方法

public Object readResovle(){
return INSTANCE;
}

如果反序列化发现readResovle返回了对象,就会把其返回的对象当做结果。

1.3、为什么设置为私有?是否能防止反射创建新的实例?

private Singleton(){}

防止多次创建对象,不能防止反射。

1.4、这样初始化是否保证单例对象创建时的线程安全?

private static final Singleton INSTANCE = new Singleton();

没有线程安全问题,静态成员变量的初始化在类加载的时候完成,由jvm保证了线程的安全。

1.5、为什么提供静态方法而不是直接将INSTANCE设置为public

提供更好的封装性,可以提供懒惰的初始化;可以提供泛型的支持;对创建单例变量有更好的控制。

2.实现二

enum singleton{
INSATCNE;
}

2.1 枚举单例是如何限制实例个数的

由枚举控制,是单实例的。

2.2 枚举单例在创建时是否有并发问题

没有。因为它也是静态成员变量。

2.3 枚举能否被反射破坏单例

不能用反射破坏。拿不到构造方法,不能实现反射。

2.4 枚举单例能否被反序列化破坏单例

枚举在实现的时候就继承了序列化的接口,不能被破坏。

2.5枚举单例属于懒汉式还是饿汉式

饿汉式的

2.6 枚举单例如果希望加入一些单例创建时的初始化逻辑该如何做

添加构造方法,实现初始化。

实现3

class Singleton {
    //1.构造器私有化,外部不能new
    private Singleton(){}

    //2.本类内部创建对象实例
    private static Singleton instance;

    //提供一个静态的公有方法,加入同步处理的代码,解决线程安全问题
    //即懒汉式
    public static synchronized Singleton getInstance(){
        if(instance == null){
            instance = new Singleton();
        }
        return instance;
    }
}
 public static synchronized Singleton getInstance(){
        if(instance == null){
            instance = new Singleton();
        }
        return instance;
    }

在上述地方会出现效率低下,第一次的访问的时候,通过同步锁创建对象,但是对象创建了之后,可以不通过同步锁访问了,同步锁的范围太大了。

4、实现4

class Singleton {
    //1.构造器私有化,外部不能new
    private Singleton(){}

    //2.本类内部创建对象实例
    private static volatile Singleton instance;

    //提供一个静态的公有方法,当使用到该方法时,才去创建instance
    //即懒汉式
    public static  Singleton getInstance(){
        if(instance == null){
            synchronized(Singleton.class){
                if(instance == null) {
                    instance = new Singleton();
                }
            }
    }
        return instance;
    }
}

4.1 为什么要加volatile?

指令可能会重排序,同步代码块可能先赋值,再去创建对象,同步代码块外面的对象可能会拿到不完整的对象。

4.2 对比实现3,说出这样做的意义

第一次调用的话,会继续创建对象,但是第二、第三次调用,可以直接判断,不用再通过同步代码了,提升了效率。

4.3 为什么还要在同步代码块中加是否为空的判断

为了防止首次多线程的调用,如果同时有两个线程都进到代码块时,可以防止多次创建对象。

5、实现五

class Singleton {
    
    private Singleton(){}

   
    private static class SingletonInstance{
        private static final Singleton INSTANCE = new Singleton();
    }

    //提供一个静态的公有方法,当使用到该方法时,才去创建instance
    //即懒汉式
    public static Singleton getInstance(){
        return SingletonInstance.INSTANCE;
    }
}

利用静态内部类特点实现延迟加载,效率高

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值