单例模式
单例模式是指在内存中只会创建且仅创建一次对象的设计模式。 在程序中多次使用同一个对象且作用相同 时,为了防止频繁地创建对象使得内存飙升,单例模式可以让程序仅在内存中创建一个对象,让所有需要调用的地方都共享这一单例对象。
懒汉式
java
public class Singleton {
private static Singleton singleton;
private Singleton(){}
public static Singleton getInstance() {
if (singleton == null) {
singleton = new Singleton();
}
return singleton;
}
}
缺点:线程安全问题
解决方案:加锁,在方法上面加锁的话并发效果不好,获取对象时要提前获取锁
在需要用到对象时才实例化对象,正确的实现方式是:Double Check + Lock,解决了并发安全和性能低下问题。
Double Check(双重校验) + Lock(加锁)
java
public class Singleton {
private static volatile Singleton singleton;
private Singleton(){}
public static Singleton getInstance() {
if (singleton == null) {
synchronized(Singleton.class) {
if (singleton == null) {
singleton = new Singleton();
}
}
}
return singleton;
}
}
饿汉式
在类加载时已经创建好该单例对象,在获取单例对象时直接返回对象即可,不会存在并发安全和性能问题。
java
public class Singleton{
private static final Singleton singleton = new Singleton();
private Singleton(){}
public static Singleton getInstance() {
return singleton;
}
}
单例模式敌不过反射和序列化
枚举
java
public enum Singleton {
INSTANCE;
public void doSomething() {
System.out.println("Singleton is doing something");
}
}
-
线程安全: 枚举类型的实例是在类加载时创建的,因此它是线程安全的。
-
简洁: 枚举实现单例是非常简洁的,不需要手动实现线程安全性和懒加载等细节。
-
防止反序列化重新创建对象: 枚举类型默认提供了一个
readResolve
方法,防止反序列化过程中重新创建新的实例。
-
在开发中如果对内存要求非常高,那么使用懒汉式写法,可以在特定时候才创建该对象;
-
如果对内存要求不高使用饿汉式写法,因为简单不易出错,且没有任何并发安全和性能问题。
-
为了防止多线程环境下,因为指令重排序导致变量报NPE,需要在单例对象上添加volatile关键字防止指令重排序。
-
最优雅的实现方式是使用枚举,其代码精简,没有线程安全问题,且 Enum 类内部防止反射和反序列化时破坏单例。