java 内部类 单例_Java单例模式的几种实现

本文详细介绍了Java中实现单例模式的五种方法:静态内部类、饿汉模式、懒汉模式、双重校验锁(DCL)懒汉模式以及枚举方式。每种方式的原理、优缺点都被逐一阐述,包括静态内部类的类加载时初始化、饿汉模式的非延迟加载、懒汉模式的同步问题、DCL懒汉模式的线程安全和高性能,以及枚举方式的天然线程安全和防止反序列化及反射破坏单例。

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

一:静态内部类实现单例模式

原理:通过一个静态内部类定义一个静态变量来持有当前类实例,在类加载时就创建好,在使用时获取。

缺点:无法做到延迟创建对象,在类加载时进行创建会导致初始化时间变长。

public classSingletonInner {private static classHolder {private static SingletonInner singleton = newSingletonInner();

}privateSingletonInner(){}public staticSingletonInner getSingleton(){returnHolder.singleton;

}

二:饿汉模式

原理:创建好一个静态变量,每次要用时直接返回。

缺点:无法做到延迟创建对象,在类加载时进行创建会导致初始化时间变长。

public classSingletonHungry {private static SingletonHungry instance = newSingletonHungry();privateSingletonHungry() {

}public staticSingletonHungry getInstance() {returninstance;

}

三:懒汉模式

原理:延迟创建,在第一次用时才创建,之后每次用到就返回创建好的。

缺点:由于synchronized的存在,多线程时效率很低。

public classSingletonLazy {private static volatileSingletonLazy instance;privateSingletonLazy() {

}public static synchronizedSingletonLazy getInstance() {if (instance == null) {

instance= newSingletonLazy();

}returninstance;

}

四:双重校验锁懒汉模式

原理:在getSingleton()方法中,进行两次null检查。这样可以极大提升并发度,进而提升性能。

public classSingleton {private static volatile Singleton singleton = null;//使用valatile,使该变量能被所有线程可见privateSingleton(){}public staticSingleton getSingleton(){if(singleton == null){synchronized (Singleton.class){//初始化时,加锁创建if(singleton == null){//为避免在加锁过程中被其他线程创建了,再作一次非空校验

singleton= newSingleton();

}

}

}returnsingleton;

}

五:上述4种方式实现单例模式的缺点

1、反序列化对象时会破环单例

反序列化对象时不会调用getXX()方法,于是绕过了确保单例的逻辑,直接生成了一个新的对象,破环了单例。

解决办法是:重写类的反序列化方法,在反序列化方法中返回单例而不是创建一个新的对象。

public class Singleton implementsjava.io.Serializable {public static Singleton INSTANCE = newSingleton();protectedSingleton() {

}//反序列时直接返回当前INSTANCE

privateObject readResolve() {returnINSTANCE;

}

}

2、在代码中通过反射机制,直接调用类的私有构造函数创建新的对象,会破环单例

解决办法是:维护一个volatile的标志变量在第一次创建实例时置为false;重写构造函数,根据标志变量决定是否允许创建。

private static volatile boolean flag = true;privateSingleton(){if(flag){

flag= false; //第一次创建时,改变标志

}else{throw new RuntimeException("The instance already exists !");

}

六:枚举模式实现单例——将单例维护在枚举类中作为唯一实例

原理:定义枚举类型,里面只维护一个实例,以此保证单例。每次取用时都从枚举中取,而不会取到其他实例。

public enumSingletonEnum {

INSTANCE;privateString name;publicString getName(){returnname;

}public voidsetName(String name){this.name =name;

}

优点:

1)使用SingletonEnum.INSTANCE进行访问,无需再定义getInstance方法和调用该方法。

2)JVM对枚举实例的唯一性,避免了上面提到的反序列化和反射机制破环单例的情况出现:每一个枚举类型和定义的枚举变量在JVM中都是唯一的。

原因:枚举类型在序列化时仅仅是将枚举对象的name属性输出到结果中,反序列化的时候则是通过java.lang.Enum的valueOf方法来根据名字查找枚举对象。

同时,编译器禁止重写枚举类型的writeObject、readObject、readObjectNoData、writeReplace和readResolve等方法。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值