单例模式
类图
定义:
确保某一个类只有一个实例,而且自行实例化并向整个系统提供这个实例
优点:
- 内存中仅一个实例,故减少了内存开支
- 由于只生成一个实例,故减少了系统性能开销(如读取配置,产生依赖对象等,利用常驻内存的方式,仅生成一个对象
- 可以避免对资源的多重占用(如只有一个实例存在,避免对同一资源文件同时写操作)缺点:
- 单例模式没有接口,扩展困难
- 与单一职责原则有冲突
使用场景
- 要求生成唯一序列号的环境
- 整个项目需要一个共享访问点或共享数据(如web页面的计数器)
- 创建一个对象需要消耗的资源过多时
懒汉,线程不安全
public class Singleton {
private static Singleton instance;
private Singleton (){}
public static Singleton getInstance() {
if (instance == null) {
instance = new Singleton();
}
return instance;
}
}
这种方法是lazy load,但是致命的问题就是线程不安全。比如我们有2个线程同时执行getInstance方法,并且同时做了 if (instance == null) 的判断。这时2个线程都认为instance没有初始化,然后它们同时初始化并返回,最后返回了不同的实例,并不是我们想要的同一个对象。
懒汉,线程安全
public class Singleton {
private static Singleton instance;
private Singleton (){}
public static synchronized Singleton getInstance() {
if (instance == null) {
instance = new Singleton();
}
return instance;
}
}
这种写法就上一种写法加上同步锁,但是效率很低,每次调用方法都有锁操作。
饿汉
public class Singleton {
private static Singleton instance = new Singleton();
private Singleton (){}
public static Singleton getInstance() {
return instance;
}
}
没有lazy load
静态内部类(推荐)
public class Singleton {
private static class SingletonHolder {
private static final Singleton INSTANCE = new Singleton();
}
private Singleton (){}
public static Singleton getInstance() {
return SingletonHolder.INSTANCE;
}
}
这种方式是java编程思想一书中提到的方法,利用ClassLoader机制保证初始化instance时只有一个线程。
枚举
public enum Singleton {
INSTANCE;
public void doSomething(){
}
}
双重校验锁
public class Singleton {
private volatile static Singleton singleton;
private Singleton (){}
public static Singleton getSingleton() {
if (singleton == null) {
synchronized (Singleton.class) {
if (singleton == null) {
singleton = new Singleton();
}
}
}
return singleton;
}
}
JDK1.5之前由于jvm方法执行顺序重排,导致依然无法实现单例,具体可以参阅Java编程思想,JDK1.5只有正常。