求学者

设计模式之单例模式

好记性不如烂笔头,总结一下自己印象深刻的设计模式,从最简单的单例模式开始吧!

简介

单例模式(Singleton Pattern) 是最简单的设计模式之一了,这种类型的设计模式属于创建者模式,这种模式是为了确保只有一个对象被创建。

特点

  1. 单例类只能有一个实例
  2. 单例类必须自己创建自己的唯一实例
  3. 单例类必须给其他对象提供着一种实例

优点

  1. 内存中只有该类的一个实例,避免全局使用的类频繁的创建销毁,浪费系统资源。
  2. 避免对资源的多重占用(写文件操作,避免对文件多重占用)。

缺点
没有接口,不能继承,与单一职责冲突,一个类应该只关心内部逻辑,不关心外面怎样实例化。

几种最佳实践

1.饿汉模式

优点:线程安全,不加锁,执行效率高。
缺点:类装载时实例化, 不能保证lazy load 效果,浪费内存。

注意

  1. 基于 classloder 机制避免了多线程的同步问题
  2. 如果调用 getInstance 方法时导致类加载,满足lazy load 载效果。

代码

1
2
3
4
5
6
7
public class Singleton {
private static Singleton instance = new Singleton();
private Singleton(){}
public static getInstance(){
return instance;
}
}

2. 懒汉模式(double-checked locking)

优点 lazy load,线程安全且保持高性能
缺点 实现较复杂

代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
public class Singleton {
// volatile 保证 new 原子性
private volatile static Singleton instance;
private Singleton (){}
public static Singleton getInstance() {
// 双校验
if (instance == null) {
synchronized (Singleton.class) {
if (instance == null) {
instance = new Singleton();
}
}
}
return instance;
}
}

3. 静态内部类模式

优点:lazy, 线程安全,实现简单,跟双检锁方式效果效果相同

注意
利用 classloder 机制保证初始化一个instance只有一个线程。

代码

1
2
3
4
5
6
7
8
9
10
public class Singleton {
private Singleton(){}
// 静态内部类
private static class SingletonFactory {
peivate static final Singleton INSTANCE = new Singleton();
}
public static final Singleton getIntance() {
return SingletonFactory.INSTANCE;
}
}

4. 枚举

优点:线程安全,简洁,自动支持序列化机制,绝对防止多次序列化,防止反序列化重新创建新的对象。

缺点: no lazy, 不能通过 reflection attack 调用私有构造。

代码

1
2
3
4
5
public enum Singleton {
INSTANCE;
public void whateverMethod() {
}
}

总结

经验之谈:

  1. 建议使用 1.饿汉模式 加载
  2. 明确需要 lazy load 使用 3.内部类模式
  3. 涉及反序列化创建对象,使用 4.枚举
  4. 有其他需求,考虑 2.双检锁懒汉模式