单例模式
实现方式
- 懒汉式-双重检查锁
public class Singleton{
private volatile static SomeClass instance;
privarte Singleton(){}
public SomeClass getInstance() {
if (null == instance) {
synchronized (Test.class) {
if (null == instance) {
instance = new SomeClass(); // code1
}
}
}
return instance;
}
注:代码code1处的实例化对象实际可以分成一下三个步骤
- 分配内存空间
- 初始化对象
- 将对象指向刚分配的内存空间
但是有些编译器为了性能的原因,可能会将第二步和第三步进行重排序,顺序就成了:
- 分配内存空间
- 将对象指向刚分配的内存空间
- 初始化对象
在多线程并发执行上述代码的情况下可能发生后续线程访问的是一个初始化未完成的对象,volatile修饰符用于防止指令重排带来的空指针问题
- 饿汉式
private class Singleton{
private Singleton(){}
private static final Singleton single=new Singleton();
public static Singleton getInstance(){
return single;
}
}
两者的区别:
- 饿汉就是类一旦加载,就把单例初始化完成,保证getInstance的时候,单例就是已经存在的;
懒汉比较懒,只有当调用getInstance的时候,才会去初始化这个单例 - 线程安全:
饿汉式天生就是线程安全的,可以直接用于多线程而不会出现问题
懒汉式本省是非线程安全的,为了实现线程安全有多种写法,在资源加载和性能方面有些区别 - 饿汉式是在类创建的同时就实例化一个静态对象出来,不管之后会不会使用这个单例,都会占据一定的内存,相应的在第一次调用时速度会更快,因为其资源已经初始化完成