Java并发编程:线程安全单例习题

文章讨论了Java中实现单例模式的多种方式,包括使用`final`关键字防止继承,通过`readResolve`防止反序列化破坏单例,以及不同类型的单例模式如枚举单例、懒汉式和饿汉式的实现和优缺点。枚举单例是线程安全且无法通过反射破坏的。文章还提到了双重检查锁和静态内部类实现单例,强调了线程安全和性能的平衡。
摘要由CSDN通过智能技术生成

1

请阅读下列代码并回答注释问题

// 问题1:为什么加 final
// 问题2:如果实现了序列化接口, 还要做什么来防止反序列化破坏单例
public final class Singleton implements Serializable {
 // 问题3:为什么设置为私有? 是否能防止反射创建新的实例?
 private Singleton() {}
 // 问题4:这样初始化是否能保证单例对象创建时的线程安全?
 private static final Singleton INSTANCE = new Singleton();
 // 问题5:为什么提供静态方法而不是直接将 INSTANCE 设置为 public, 说出你知道的理由
 public static Singleton getInstance() {
 return INSTANCE;
 }
 public Object readResolve() {
 return INSTANCE;
 }
}

问题1

为了防止子类继承 Singleton 重写类方法

问题2

readResolve 可以防止反序列化生成新对象 用的是readResolve 返回的实例

问题3

不能,反射是不用走构造方法的,枚举可以防反射

问题4

通过静态方法更适合解耦和懒惰创建实例

2

请阅读下列代码并回答注释问题

// 问题1:枚举单例是如何限制实例个数的(不限制)
// 问题2:枚举单例在创建时是否有并发问题(不会,因为类加载只会执行1次)
// 问题3:枚举单例能否被反射破坏单例(不能)
// 问题4:枚举单例能否被反序列化破坏单例(不能)
// 问题5:枚举单例属于懒汉式还是饿汉式(饿汉式)
// 问题6:枚举单例如果希望加入一些单例创建时的初始化逻辑该如何做
enum Singleton {
 INSTANCE;
}

问题6

可以加构造方法进行初始化,具体参考java 枚举类型 构造方法

3

public final class Singleton {
 private Singleton() { }
 private static Singleton INSTANCE = null; // 不能锁INSTANCE,后面会赋值
 // 分析这里的线程安全, 并说明有什么缺点
 public static synchronized Singleton getInstance() {
 if( INSTANCE != null ){
 return INSTANCE;
 }
 INSTANCE = new Singleton();
 return INSTANCE;
 }
}

这是一个懒汉式单例,synchronized 注意需要锁引用不能是null的对象,否则会报空指针异常NullPointerException

缺点是锁的范围比较大,每次调用getInstance都需要加锁

4

public final class Singleton {
    private Singleton() { }
    // 问题1:解释为什么要加 volatile ?
    private static volatile Singleton INSTANCE = null;

    // 问题2:对比实现3, 说出这样做的意义
    public static Singleton getInstance() {
        if (INSTANCE != null) {
            return INSTANCE;
        }
        synchronized (Singleton.class) {
            // 问题3:为什么还要在这里加为空判断, 之前不是判断过了吗
            if (INSTANCE != null) { // t2
                return INSTANCE;
            }
            INSTANCE = new Singleton();
            return INSTANCE;
        }
    }
}

是个双重检查锁实现单例的例子

问题1

INSTANCE没有被synchronized完全包裹,加volatile是为了保证不在锁内进行重排序

问题2

意义在于第一次加锁获得实例后后续直接进入if判断拿到实例,就不用加锁了

问题3

锁内加if判断是为了防止首次加锁2个线程进入创建2个实例的情况

5

public class Singleton5 {

    private Singleton5(){
    }

    private static Singleton5 singleton5;

    public static Singleton5 getInstance(){
        return SingletonHander.singleton;
    }

    private static class SingletonHander{
        private static final Singleton5 singleton = new Singleton5();
    }
}

静态内部类实现方式,由于静态内部类只会实例化1次,每次拿到的都是同一个对象,都是静态常量

并且该方法线程安全,并且是懒汉式,推荐使用

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值