java 单例模式指整个程序中只有一个某个类的实例,通常被用来代表那些本质上唯一的系统组件,比如窗口管理器或者文件系统。
《Effective Java》里面的三种方法:
- 公有的静态成员:
public class Elvis {
public static final Elvis INSTANCE = new Elvis();
private Elvis() {
}
public void leaveTheBuilding() {
}
}
- 静态工厂方法
public class Elvis {
private static final Elvis INSTANCE = new Elvis();
private Elvis() {
}
public static Elvis getInstance() {
return INSTANCE;
}
public void leaveTheBuilding() {
}
}
工厂方法有两个优势,一是可以改成每个调用该方法的线程都返回一个唯一的实例,二是与泛型有关。
- 使用单元素枚举类型
public enum Elvis {
INSTANCE;
public void leaveTheBuilding() {
}
}
这种方法更加简介,而且无偿提供了序列化机制。
其他常用方法
- 在工厂方法中初始化单例,按需延迟加载单例
public class Singleton {
private static Singleton instance = null;
private Singleton() {
}
public static Singleton newInstance() {
if (instance == null) {
instance = new Singleton();
}
return instance;
}
}
- 第一种方法叫做“懒汉式”加载,多个线程调用newInstance方法会产生多个实例。Effective Java 中的第一、二种方法叫做“饿汉式”加载,在多线程的情况下不会出现问题,因为JVM只会加载一次单例类。可以使用同步锁来解决多线程不安全的问题。
public class Singleton {
private static Singleton instance = null;
private Singleton() {
}
public static Singleton newInstance() {
synchronized(Singleton.class) {
if (instance == null) {
instance = new Singleton();
}
return instance;
}
}
}
- 双重校验锁方式,可以在上面方法外层加个if语句来提高性能,防止每次通过同步锁来获取单例。
public class Singleton {
private static volatile Singleton instance = null;
private Singleton() {
}
public static Singleton newInstance() {
if (instance == null) {
synchronized(Singleton.class) {
if (instance == null) {
instance = new Singleton();
}
}
}
return instance;
}
}
注意 instance 是 volatile 变量,保证“对 volatile 变量的写操作,不允许和它之前的读写操作打乱顺序;对 volatile 变量的读操作,不允许和它之后的读写乱序”。
对 volatile 变量的读写操作是一个比较重的操作,上面的方法还可以通过局部变量来优化:
public class Singleton {
private static volatile Singleton instance = null;
private Singleton() {
}
public static Singleton newInstance() {
Singleton inst = instance;
if (inst == null) {
synchronized(Singleton.class) {
inst = instance;
if (inst == null) {
inst = new Singleton();
instance = inst;
}
}
}
return inst;
}
}
- 静态内部类方式
public class Singleton {
private static class SingletonHolder {
public static Singleton instance = new Singleton();
}
private Singleton() {
}
public static Singleton newInstance() {
return SingletonHolder.instance;
}
}
JVM进行类加载的时候会保证数据是同步的,内部类只有在使用时才会加载,实现了“懒汉式”的加载和线程安全。
参考文章
- 《Effective Java》
- Java 单例真的写对了么?
- 你真的会用单例模式吗