放眼所有的设计模式,感觉单例模式应该是最好理解也用的比较广的一种模式了。
单例模式是什么
单例模式是让当前的单例对象在运行中只存在一份,即将构造方法私有化,创建私有的静态对象,提供公有的静态方法去获得此对象。
//饿汉单例模式
public class SingleUtil {
private static SingleUtil mInstance = new SingleUtil();
private SingleUtil(){}
public static SingleUtil getInstance() {
return mInstance;
}
}
上面这个就是最简单的饿汉单例模式的例子。
单例模式的几种实现
单例模式最常见的就是懒汉单例和饿汉单例,顾名思义,饿汉就是饥渴难耐,声明对象时就把对象实例new出来(上面的例子),懒汉就是懒得要命,声明对象不去new,等后面运行中再去new出实例对象。
饿汉单例很简单,不会对线程造成任何影响,就是生命周期会比懒汉的长。
懒汉单例就复杂一些了,由于实现了懒加载,容易引起一些线程的问题。
//懒汉单例模式
public class SingleUtil {
private static SingleUtil mInstance;
private SingleUtil(){}
public static SingleUtil getInstance() {
if (mInstance == null) {
mInstance = new SingleUtil();
}
return mInstance;
}
}
上面这种就是线程不安全的懒汉单例了,比如两个线程A和B都执行到if判断语句结束后,A抢占CPU会new一个实例,然后B又抢占CPU就又会new一个实例,导致出现问题。当然,如果你的程序百分百不会出现多线程,那么这个写法是性能上最好的了。
真遇到多线程问题的话一般会使用双检锁懒汉单例:
//懒汉双检锁单例模式
public class SingleUtil {
private volatile static SingleUtil mInstance;
private SingleUtil(){}
public static SingleUtil getInstance() {
if(mInstance == null){ //第一层检查
synchronized (SingleUtil.class) {
if(mInstance == null){ //第二层检查
mInstance = new SingleUtil();
}
}
}
return mInstance;
}
}
两次检查应该很好理解,唯一的volatile关键字有点复杂,涉及到了jvm的底层的原子操作,volatile的特性是禁止指令重排序,我自己都没搞明白,就不瞎哔哔了。