1、懒汉式
①.懒汉式-线程不安全
- 线程不安全,Lazy加载
- 这种方式是最基本的实现方式,这种实现最大的问题就是不支持多线程
因为没有加锁 synchronized,所以严格意义上它并不算单例模式。
`java
public class SlackerThreadNoSafe {
private static SlackerThreadNoSafe slackerThreadNoSafe;private SlackerThreadNoSafe() {
}public static SlackerThreadNoSafe getInstance() {
if (slackerThreadNoSafe == null) { slackerThreadNoSafe = new SlackerThreadNoSafe(); } return slackerThreadNoSafe;}
}
#### ②.懒汉式-线程安全
* 线程安全,Lazy加载
* 这种方式具备很好的 lazy loading,能够在多线程中很好的工作,但是效率很低.
* 优点:第一次调用才初始化,避免内存浪费。
* 缺点:必须加锁 synchronized 才能保证单例,但加锁会影响效率。
``` java
public class SlackerThreadSafe {
private static SlackerThreadSafe slackerThreadSafe;
private SlackerThreadSafe() {
}
public static synchronized SlackerThreadSafe getInstance() {
if (slackerThreadSafe == null) {
slackerThreadSafe = new SlackerThreadSafe();
}
return slackerThreadSafe;
}
}
2、饿汉式
- 线程安全,非Lazy加载
- 优点:没有加锁,执行效率会提高。
缺点:类加载时就初始化,浪费内存。
public class StarvingModel { private static StarvingModel starvingModel = new StarvingModel(); private StarvingModel() { } public static StarvingModel getInstance() { return starvingModel; } }
3、双检锁/双重校验锁
- 线程安全, Lazy加载
这种方式采用双锁机制,安全且在多线程情况下能保持高性能
public class DoubleCheckedLocking { private static DoubleCheckedLocking doubleCheckedLocking; private DoubleCheckedLocking(){} public static DoubleCheckedLocking getInstance(){ if (doubleCheckedLocking == null){ synchronized (DoubleCheckedLocking.class){ if (doubleCheckedLocking == null){ doubleCheckedLocking = new DoubleCheckedLocking(); } } } return doubleCheckedLocking; } }
4、登记式/静态内部类
- 线程安全 Lazy加载
- 因为类在初始化的时候会获得一个锁,而读取静态变量是触发类初始化的条件
`java
public class InnerClassModel {
private static class Single{
}private static final InnerClassModel INNER_CLASS_MODEL = new InnerClassModel();
private InnerClassModel(){}
public static final InnerClassModel getInstance(){
}return Single.INNER_CLASS_MODEL;
}
## 5、枚举
* 线程安全.非Lazy加载
* 自动支持序列化机制,防止反序列化重新创建新的对象
* 绝对防止多次实例化
```java
public enum EnumModel {
INSTANCE;
public void doSomeThing() {
}
// you can use EnumModel.INSTANCE.doSomeThing();
// you can only be a single case.
}
6、总结
- 菜鸟说: 一般情况下,不建议使用懒汉式,建议使用饿汉式。只有在要明确实现 lazy loading 效果时,才会使用登记式。如果涉及到反序列化创建对象时,可以尝试使用枚举式。如果有其他特殊的需求,可以考虑使用双检锁式。