前言
单例模式是在面试中是最容易被考到的设计模式,这是因为单例模式是设计模式中最简单的,几行代码就能搞定(现场手写代码);同时单例模式又有多种实现方式,涉及到线程安全、懒加载、序列化等问题。
单例模式一共分为5种:
- Eager initialization(饿汉模式)
- Lazy initialization(懒汉模式)
- double-checked locking(双重加锁)
- Initialization-on-demand holder idiom(静态内部类)
- The enum way(枚举)
饿汉模式
代码
// 饿汉模式,开始就创建实例,线程安全
public class Wife1 {
private static final Wife1 wife = new Wife1();
private Wife1() {}
public static Wife1 getWife() {
return wife;
}
}
说明
- 在类加载之后、被任何线程使用之前,static 的变量 INSTANCE 就已经定义好。
- 方法getInstance()
不需要同步
,所有的线程都会看到同样的实例。 - 关键字
final
使得 INSTANCE 不能修改,保证有且只有一个实例。
懒汉模式
代码
// 懒汉模式,需要时才创建实例,需加锁
public class Wife2 {
private static Wife2 wife;
private Wife2() {}
public static synchronized Wife2 getWife() {
if (wife == null) {
wife = new Wife2();
}
return wife;
}
}
说明
- 获得实例方法是
线程同步
的,效率低
双重加锁
代码
// 双重加锁,通过volatile关键字防止编译器重排序,Java 1.5以下不可用
public class Wife3 {
private volatile static Wife3 wife;
private Wife3() {}
public static synchronized Wife3 getWife() {
if (wife == null) {
synchronized (Wife3.class) {
if (wife == null) {
wife = new Wife3();
}
}
}
return wife;
}
}
说明
- 只有在第一次时,才会同步类,效率高
-
volatile
关键字,在Java 1.5以下不可用
静态内部类
代码
// 静态内部类
public class Wife4 {
// 只有在需要时,才被JVM加载。加载类Wife4时,不加载内部类WifeHolder
private static class WifeHolder {
private static final Wife4 wife = new Wife4();
}
private Wife4() {}
public static Wife4 getWife() {
return WifeHolder.wife;
}
}
说明
- 尽可能
延迟加载
- 适用于
所有的Java版本
线程安全
枚举
代码
// 枚举,《Effective Java》推荐方法,最简单、线程安全
public enum Wife5 {
INSTANCE;
}
说明
- 实现极其简单
- Java 1.5及以上
线程安全
网友评论