1.概念
确保某一个类只有一个实例,而且自行实例化并向整个系统提供这个实例。
2.角色构成
1)Sinleton单例类:通过使用private的构造函数确保了在一个应用中只产生一个实例,并且自行实例化。
3.通用源码
public class Singleton {
private static final Singleton singleton = new Singleton();
//限制产生多个对象
private Singleton() {
}
//通过该方法获得实例对象
public static Singleton getSingleton() {
return singleton;
}
//类中的其他方法,尽量是static
public static void doSomething() {
}
}
4.优点
1)由于单例模式在内存中只有一个实例,减少了内存开支。
2)由于单例模式只生成一个实例,所以减少了系统的性能开销。
3)单例模式可以避免对资源的多重占用。
4)单例模式可以在系统设置全局的访问点,优化和共享资源访问。
5.缺点
1)单例模式没有借口,扩展很困难。
2)单例模式对测试是不理的。
3)单例模式与单一职责原则有冲突。
6.使用场景
1)要求生成唯一序列号的环境。
2)在整个项目中需要一个共享访问点或共享数据。
3)创建一个对象需要消耗的资源过多。
4)需要定义大量的静态常量和静态方法的环境。
7.不同实现
1)懒汉,线程安全
public class Singleton {
private static Singleton instance = null;
private Singleton (){}
public static synchronized Singleton getInstance() {
if (instance == null) {
instance = new Singleton();
}
return instance;
}
}
2)饿汉
public class Singleton {
private static Singleton instance = new Singleton();
private Singleton (){}
public static Singleton getInstance() {
return instance;
}
}
类加载时即实例化instance
3)静态内部类
public class Singleton {
private static class SingletonHolder {
private static final Singleton INSTANCE = new Singleton();
}
private Singleton (){}
public static final Singleton getInstance() {
return SingletonHolder.INSTANCE;
}
}
Singleton类被装载,instance不一定被初始化,只有显示通过调用getInstance方法时,才会显示装载SingletonHolder类,从而实例化instance
4)枚举
public enum Singleton {
INSTANCE;
public void whateverMethod() {
}
}
可以避免多线程同步问题,而且还能防止反序列化重新创建新的对象。
5)双重校验锁
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;
}
}
volatile的必要性:instance = new Singleton();并不是原子操作,而是分为:
1 为对象分配内存
2 初始化实例对象
3 把引用instance指向分配的内存空间
这三个步骤不能保证按序执行,处理器回进行指令重排序优化,可能为1,3,2的顺序,在执行分配内存空间时,别的线程会直接返回还没初始化完毕的instance引用,可能回造成程序奔溃。volatile可以保证多线程环境下,变量的修改可见性。
注:
1.如果单例由不同的类装载器装入,那便有可能存在多个单例类的实例。
2.如果Singleton实现了Serializable接口,那么这个类的实例可能被序列化和复原。
解决方法
public class Singleton implements java.io.Serializable {
public static Singleton INSTANCE = new Singleton();
protected Singleton() {
}
private Object readResolve() {
return INSTANCE;
}
}
8.最佳实践
1)Spring中,每个Bean默认就是单例的,Spring容器可以管理这些Bean的生命周期。