模式介绍
单例模式是指整个类只有一个实例对象
一般用于减少重量级对象频繁创建的开销; 或对象太多, 减少内存占用
代码实现
方法一: 饿汉式
1
2
3
4
5
6
7
8
9
10
public class Singleton1 {
private final static Singleton1 INSTANCE = new Singleton1();
private Singleton1(){}
public static Singleton1 getInstance(){
return INSTANCE;
}
}
优点: 实现简单
缺点: 类装载阶段完成对象创建; 如果类一直没有使用, 会浪费内存
方法二: 懒汉式
1
2
3
4
5
6
7
8
9
10
11
12
13
public class Singleton2 {
private static Singleton2 singleton;
private Singleton2() {}
public static Singleton2 getInstance() {
if (singleton == null) {
singleton = new Singleton2(); // 线程不安全; 可能会创建多个
}
return singleton;
}
}
优点: Lazy Loading
缺点: 多线程不安全
方法三: 懒汉式-方法级同步
1
2
3
4
5
6
7
8
9
10
11
12
13
public class Singleton3 {
private static Singleton3 singleton;
private Singleton3() {}
public static synchronized Singleton3 getInstance() {
if (singleton == null) {
singleton = new Singleton3();
}
return singleton;
}
}
优点: 在上面的懒汉式基础上加了synchronized, 保证了线程安全
缺点: 性能太低, 即使已经创建好了, 每次执行getInstance
方法还是要获取锁
方法四: 懒汉式-双重检测
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
public class Singleton4 {
private static volatile Singleton4 singleton; // volatile作用?
private Singleton4() {}
public static Singleton4 getInstance() {
if (singleton == null) {
synchronized (Singleton4.class) {
if (singleton == null) {
singleton = new Singleton4();
}
}
}
return singleton;
}
}
优点: 线程安全, 性能好, Lazy Loading
缺点: 实现复杂
方法五: 静态内部类
1
2
3
4
5
6
7
8
9
10
11
12
public class Singleton5 {
private Singleton5() {}
private static class SingletonInstance {
private static final Singleton5 INSTANCE = new Singleton5();
}
public static Singleton5 getInstance() {
return SingletonInstance.INSTANCE;
}
}
通过JVM的静态属性只会在类加载时初始化一次
规则保证了INSTANCE的线程安全
优点: 线程安全, Lazy Loading, 无锁, 实现较双重检验简单
方法六: 枚举方法
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
public enum SingletonFactory {
XXXHolder(new XXX()), // 注意, 只要SingletonFactory类被加载, 里面所有枚举的instance就创建了
YYYHolder(new YYY()), // 注意, 如果想分别Lazy Loading, 就分开创建不同的枚举工厂类
;
private Object instance;
private SingletonFactory(Object instance) {
this.instance = instance;
}
public <T> T getInstance() {
return (T)instance;
}
}
优点: 线程安全, Lazy Loading, 无锁, 实现简单
典型应用
- 减少对象内存占用
- Spring里的IOC Bean默认都是单例模式
- 创建成本比较重的对象
- Mybatis里SqlSessionFactory对象
- 减少多线程竞争
- 待补充