单例设计模式, 你知道几种?

本文深入探讨了单例模式的本质及其实现方式,包括饿汉式、懒汉式、双重检查锁定(DCL)、初始化按需(InitOnDemand)及枚举式等五种常见形式,并分析了序列化对单例的影响及解决方案。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

单例又称单态, 它是和多态相对的.

本质:每一个ClassLoader中指定class创建的实例有且仅有一个.

JDK自带的类有Runtime, 它就是一个典型的单例.

常用的单例的形式有:

image

Runtime就是饿汉式.

1. 饿汉式

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

2.懒汉式

public class Singleton {
private static Singleton instance = null;
private Singleton() {
}
public static synchronized Singleton getInstance() {
if (instance == null)
instance = new Singleton();
return instance;
}
}

3. DCL

double-checked locking, 它是懒汉式的变体, 主要是为了提高懒汉式的效率. 在jdk1.5之前使用, 会有问题, 由于当时的内存模型(JMM)决定.

因为class代码经过 java 类名    运行时, 为了提速会被JIT转成真正cpu的代码再执行, 这个过程中很可能会对class文件执行的顺序进行优化合并.

具体的在windows中可以将hsdis-i386.dll放到jdk1.7.0/jre/bin/client,和jdk1.7.0/jre/bin/server中, 然后再输入

java -XX:+UnlockDiagnosticVMOptions -XX:+PrintAssembly  MyClassName查看

在jdk1.5+时, 对于遇到volatile 时, 其涉及到的方法不会进行优化合并, 所以能保证//2 //3执行的顺序.

public class Singleton {
private static volatile Singleton instance = null;
private Singleton() {
}
public static Singleton instance() {//1
if (instance == null) {//2
synchronized (Singleton.class) {
if (instance == null) {//3
instance = new Singleton();
}
}
}
return instance;
}
}

4.Init On Demand

解决DCL的缺陷, 可以在jdk1.2+使用, 由研究员Bill Pugh提出

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

5. 枚举式

最简单的单态, Josh Bloch强烈推荐!

public enum Singleton {
INSTANCE;
}

到这儿为止, 单例讨论完了吗?

提个问题, 单例会不会产生多个对象??

在实际的工作中, 类经常要implements Serializable? 然后再进行对象序列化, 和反序列化

反序列化它可是一个隐含的构造器? 反序列化一下, 单例就失败了.如何解决呢?

常用的方法有两种:

一. readResolve

public class Singleton implements Serializable {
private static final Singleton INSTANCE = new Singleton();
private Singleton() {
}
private Object readResolve() {
//readUnshared 返回该对象的浅表副本
return INSTANCE;
}
public static Singleton getInstance() {
return INSTANCE;
}
}

红色代码非常重要, 当进行反序列化时,  ois.readObject();时内部就是通过反射检查implements Serializable的类有没有

readResolve方法,如果有就把readResolve的返回值作为ois.readObject();的返回值. 所以readResolve必须返回之前对象的引用

二. 使用枚举式

使用了枚举特有的特性, 枚举序列化, 反序列化的对象然后是同一个对象. 可以自行查看ois.readObject();oos.writeObject(obj)代码, 它是

把枚举作为一种类型单独考虑的.

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值