单例模式
Tags
#设计模式
1、场景类
//单例模式-场景类
public class SingletonClient {
public static void test() {
ISingleton iSingleton=Singleton05.getInstance();
iSingleton.doSomeThing();
}
}
2、接口
//其实没啥卵用,只是为了测试方便加的
public interface ISingleton {
void doSomeThing();
}
3、几种不同的单例模式
1.饿汉式
2.懒汉式
3.双重锁定式
4.静态内部类式
5.枚举式
1.饿汉式-占内存,用空间换时间
public class Singleton01 implements ISingleton {
private static Singleton01 instance = new Singleton01();
/**
* 禁止外部创建
*/
private Singleton01() {
}
public static Singleton01 getInstance() {
return instance;
}
@Override
public void doSomeThing() {
LogUtil.e("我在做事……");
}
}
2.懒汉式-每次都要同步,浪费时间
public class Singleton02 implements ISingleton {
private static Singleton02 instance ;
/**
* 禁止外部创建
*/
private Singleton02() {
}
public static synchronized Singleton02 getInstance() {
if(instance==null){
instance=new Singleton02();
}
return instance;
}
@Override
public void doSomeThing() {
LogUtil.e("我在做事……");
}
}
3.双重锁定式-会遇到DCL失效
public class Singleton03 implements ISingleton {
private static Singleton03 instance;
/**
* 禁止外部创建
*/
private Singleton03() {
}
public static Singleton03 getInstance() {
//第一层避免不必要的线程同步
if (instance == null) {
synchronized (Singleton03.class) {
//第二层为空则创建实例
if (instance == null) {
instance = new Singleton03();
}
}
}
return instance;
}
@Override
public void doSomeThing() {
LogUtil.e("我在做事……");
}
}
什么是DCL失效?
new Instance()到底发生了什么?
memory = allocate(); //1:分配对象的内存空间
ctorInstance(memory); //2:初始化对象
instance = memory; //3:设置instance指向刚分配的内存地址
上面的伪代码中2、3步可能重排。
./_image/2016-10-29-10-33-18.png
DCL失效的解决方案:
Java5以后的版本,可以利用volatile关键字。
Why?
在java5以前,volatile原语不怎么强大,只能保证对象的可见性
但在java5之后,volatile语义加强了,被volatile修饰的对象,将禁止该对象上的读写指令重排序
这样,就保证了线程B读对象时,已经初始化完全了
4.静态内部类式-反序列化会重建实例
public class Singleton04 implements ISingleton {
private static Singleton04 instance ;
/**
* 禁止外部创建
*/
private Singleton04() {
}
public static Singleton04 getInstance() {
return SingletonHolder.instance;
}
public static class SingletonHolder{
private static final Singleton04 instance=new Singleton04();
}
@Override
public void doSomeThing() {
LogUtil.e("我在做事……");
}
}
5.枚举式-暂无明显缺点,不过也比较占内存吧
public enum Singleton05 implements ISingleton {
INSTANCE;
/**
* 禁止外部创建
*/
private Singleton05() {
}
public static Singleton05 getInstance() {
return INSTANCE;
}
@Override
public void doSomeThing() {
LogUtil.e("我在做事……");
}
}