特点
- 在Java应用中,单例模式能保证在一个JVM中,该对象只有一个实例存在
- 构造器必须是私有的,外部类无法通过调用构造器方法创建该实例
- 没有公开的set方法,外部类无法调用set方法创建该实例
- 提供一个公开的get方法获取唯一的这个实例
好处
- 某些类创建比较频繁,对于一些大型的对象,这是一笔很大的系统开销
- 省去了new操作符,降低了系统内存的使用频率,减轻GC压力
- 系统中某些类,如spring里的controller,控制着处理流程,如果该类可以创建多个的话,系统完全乱了
- 避免了对资源的重复占用
实现
饿汉式
// 1、为什么使用final:防止子类覆盖父类方法破坏单例
// 2、如果实现了序列化,如何防止反序列化破坏单例:加入readResolve方法,在反序列化时就会采用readResolve返回的对象,而不是反序列化生成的对象
public final class SingleEhan implements Serializable {
//3、构造方法为什么为私有:防止使用者使用构造器创建对象,破坏单例。
//4、能否防止反射:不能,设置accessable为true通过构造方法反射依然会获得对象
private SingleEhan() {
}
//5、这样初始化单例能否保证单例对象创建时的线程安全:可以,静态成员变量,在类初始化的时候创建。由jvm保证线程安全,会造成内存浪费
private static final SingleEhan singleEhan = new SingleEhan();
// 6、为什么使用方法而不是直接将singleEhan设置为public:为了更好的封装,可以改写成懒惰初始化。也可以支持泛型。方法中可以写一些别的逻辑
public static SingleEhan getSingleEhan() {
return singleEhan;
}
public Object readResolve() {
return singleEhan;
}
}
懒汉式
public final class SingleLanHan {
private static SingleLanHan singleLanHan = null;
private SingleLanHan() {
}
//此处能否保证线程安全:可以,因为创建对象或者获得对象会加锁。但是,锁的范围较大,就算对象创建好了,以后获得对象也要加锁,性能较低!
public static synchronized SingleLanHan getSingleLanhan() {
if (singleLanHan != null) {
return singleLanHan;
}
singleLanHan = new SingleLanHan();
return singleLanHan;
}
}
双重检查(DCL)
public final class SingleDcl {
// 1、此处为何要用volatile:防止singleDcl 在实例化的时候指令重排,导致别的线程获得实例的时候虽不为空,但还未赋值。
private static volatile SingleDcl singleDcl = null;
private SingleDcl() {
}
// 2、对比单纯的懒汉式,这里有什么优点:初始化成功后,都不用上锁
public static SingleDcl getSingleDcl() {
if(singleDcl!=null) {
return singleDcl;
}
synchronized (SingleDcl.class) {
// 3、此处为什么还要为空判断:因为首次初始化时都会进入到同步块。
if(singleDcl!=null) {
return singleDcl;
}
singleDcl = new SingleDcl();
}
return singleDcl;
}
}
静态内部类
public final class SingleInnerClass {
private SingleInnerClass() {
}
// 1、属于懒汉式还是饿汉式:懒汉式创建,类加载是懒惰的,在调用时静态变量才会初始化。
private static class LazyHolder {
static final SingleInnerClass singleInnerClass = new SingleInnerClass();
}
// 2、在创建单例时是否有并发问题:没有,初始化属于静态变量初始化,由jvm保证线程。
public static SingleInnerClass getSingleInnerClass() {
return LazyHolder.singleInnerClass;
}
}
枚举
public enum SingleEnum {
INSTANCE;
public void doSomething() {
}
}