Java单例模式可能是最简单也是最常用的设计模式,一个完美的单例需要做到哪些事呢?
- 单例(这不是废话吗)
- 延迟加载
- 线程安全
- 没有性能问题
- 防止序列化产生新对象
- 防止反射攻击
可以看到,真正要实现一个完美的单例是很复杂的,那么,让我这个司机带大家看一看正确姿势的单例。
最佳实践单例之枚举
没错,直接就上最佳实践,就是这么任性
这货长这样:
public enum Singleton{
INSTANCE;
}
如果你不熟悉枚举,可能会说:这货是啥?!
这种方式的好处是:
- 利用的枚举的特性实现单例
- 由JVM保证线程安全
序列化和反射攻击已经被枚举解决
调用方式为Singleton.INSTANCE, 出自《Effective Java》第二版第三条: 用私有构造器或枚举类型强化Singleton属性。
关于单例最佳实践的讨论可以看Stackoverflow:what-is-an-efficient-way-to-implement-a-singleton-pattern-in-java
下面将会介绍更为常见的单例模式,但是均未处理反射攻击,如果想了解更多可以看这篇文章:如何防止单例模式被JAVA反射攻击
public class Singleton {
private static final Singleton INSTANCE = new Singleton();
// 私有化构造函数
private Singleton(){}
public static Singleton getInstance(){
return INSTANCE;
}
}
这种单例的写法最简单,但是缺点是一旦类被加载,单例就会初始化,没有实现懒加载。而且当实现了Serializable接口后,反序列化时单例会被破坏。
实现Serializable接口需要重写readResolve,才能保证其反序列化依旧是单例:
public