正常的单例模式如下所示:
public class SingleTon {
private volatile static SingleTon sInstance;
private SingleTon() {
}
public static SingleTon getInstance() {
if (sInstance == null) {
synchronized (SingleTon.class) {
if (sInstance == null) {
sInstance = new SingleTon();
}
}
}
return sInstance;
}
}
关于这段代码,有些问题和理解:
1、私有化构造函数,保证了其他类调用的时候不能通过这种方式初始化获得对象。
2、提供一个公共的静态方法获取实例对象。此时为何要进行两次判空操作呢?
a、第一次判空操作是为了避免每次都执行synchronized同步锁的操作,synchronized是很消耗性能的操作,
如果第一次不为空,则不用去执行同步锁操作。
b、synchronized可以保证每个时刻只有一个线程执行同步代码,准确的说是保证线程间的有序性操作。
c、第二次判空则是防止多个类都调用该方法时,多次获取实例对象。如果已经实例化后,则此时不会再实例化对象。
3、synchronized方法里的SingleTon.class可以换成SingleTon.this吗?答案是不可以。
原因是synchronized同步块括号中的锁定对象是采用的一个无关的Object类实例,而不是采用this,
因为getInstance是一个静态方法,在它内部不能使用非静态的或者未实例的类对象
4、volatile 关键字
首先,sInstance = new SingleTon();这句话做了哪些事情
a、给sInstance实例分配内存。
b、初始化SingleTon()成员变量。
c、将sInstance对象指向new Singleton()分配的内存空间,所以这个时候sInstance就不为null了。
此时问题出现了,如果按照abc顺序执行,则一切正常,但是JVM有指令重排序的优化,所以有可能会按
照acb的顺序执行,那这样就出现问题了。volatile就是防止重排序的,这样就能正常获取单例了。
关于单例的学习笔记,便于以后回顾