java多线程-线程安全单例模式(更新中)

单例模式概述

单例模式有很多实现方法,饿汉、懒汉、静态内部类、枚举类,试分析每种实现下获取单例对象即调用getInstance)时的线程安全,并思考注释中的问题

  • 饿汉式:类加载就会导致该单实例对象被创建
  • 懒汉式:类加载不会导致该单实例对象被创建,而是首次使用该对象时才会创建

饿汉单例

public final class Singleton implements Serializable {
	privateSingleton() {}
	private static final Singleton INSTANCE=newSingleton();
	public static Singleton getInstance() {
		return INSTANCE;
		}
	public Object readResolve() { 
		return INSTANCE; 
		}
	}

问题1:为什么加 final?

  • 单例模式,设计的初衷就为了只被加载一次
  • 使用final,更好防止被其他类继承,或重写,造成反复加载情况的出现。

问题2:如果实现了序列化接口, 还要做什么来防止反序列化破坏单例?

  • 使用 public Object readResolve() {
    return INSTANCE;
    }方法来使其在反序列化的时候,返回的是已经创建的对象实例,从而防止反序列化来破坏单例模式。

问题3:为什么设置为私有? 是否能防止反射创建新的实例?

  • 设置成私有的,是为了防止被其他线程,主动调用
  • 不能防止反射来创建新的实例对象。

问题4:这样初始化是否能保证单例对象创建时的线程安全?

  • 可以保证单例对象创建时的线程安全,
  • 因为这里是静态方法来创建单例对象,其在jvm的类加载系统的初始化阶段被加载,被jvm身创建的构造器来进行初始化操作,而jvm创建的构造器是线程安全的,其被synchronized(){} 修饰,
  • 但是在工具查看字节码的时候查看到并没有被synchronized(){}修饰,因为这里的是被隐形修饰,不会显示出来。

问题5:为什么提供静态方法而不是直接将 INSTANCE 设置为 public, 说出你知道的理由?

  • 可以对我们的单例对象的获取,设置更多的条件,和可扩展性。

枚举单例

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

问题1:枚举单例是如何限制实例个数的

  • 其只有一个私有构造器,有一个静态初始化块,在类初始化阶段对枚举类的实例进行初始化,这些非常符合恶汉式单例模式的构造方式,我们都知道静态的 构造器,在多线程的环境下,也只能被执行1次;枚举通过静态方法的加载方法,来满足,限制实例个数为单例的目的。

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

  • 没有并发问题,因为枚举创建时属于静态加载,在中完成创建

问题3:枚举单例能否被反射破坏单例

  • 不会,其在IO类中和反射类中的天然安全检查优势

问题4:枚举单例能否被反序列化破坏单例

  • 不会被反序列化破坏,能防止反序列化重新创建新的对象

问题5:枚举单例属于懒汉式还是饿汉式

  • 属于饿汉式, 其只有一个私有构造器,有一个静态初始化块,在类初始化阶段对枚举类的实例进行初始化,这些非常符合饿汉式单例模式的构造方式

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

  • 在内部加构造方法

懒汉单例

DCL懒汉单例

静态内部类懒汉单例

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值