您的位置:首页 > 其它

【读书】二、单例模式

2016-02-19 23:34 309 查看
特点:

1.构造函数不外放,一般都是private

2.通过暴露一个public的静态方法或者枚举来返回一个单例对象

3.在多线程环境下面,确保单例类对象有且只有一个

4.确保单例类对象再反序列化时候不会重新构建对象

懒汉模式:

public class Singleton{
private static Singleton instance;
//1.构造函数不对外开放
private Singleton{
}
//2.通过一个静态方法来返回单例类对象
//3.加了synchronized,在多线程访问的时候,同一时刻只能有一个线程能够用synchronized修饰的方法或者代码块。
//也就是getInstance是一个同步方法,保证多线程下对象唯一
public static synchronized Singleton getInstance(){
if(instance == null){
instance = new Singleton();
}
return instance;
}

}


优点:需要时候才实例化,节约资源

缺点:每次调用getInstance()都要同步,造成不必要的同步开销

Double checkLock实现单例:

public class Singleton{
private volatile static Singleton singleton;
private Singleton (){}
public static Singleton getInstance() {
//第一层判空是为了避免不必要的同步
//从而只有第一次的时候才会加锁,之后就不会加锁
if (singleton == null) {
synchronized (Singleton.class) {
if (singleton == null) {
//第二层判空是为了在null的情况下创建实例
singleton = new Singleton();
}
}
}
return singleton;
}
}


注意DCL是有问题的:

singleton = new Singleton();


这句并不是原子操作,它可以拆分三件事:

(1).给Singleton的实例分配内存

(2).调用Singleton的构造函数,创建对象

(3).将singleton的对象指向内存分配的空间

但是,由于Java编译器允许处理器乱序执行,以及JDK1.5之前JVM中Cache,寄存器以及主内存回写顺序的规定,(2)与(3)的顺序不是固定的,

所以可能执行顺序是123,也可能是132

如果是132,那么此时比如A线程执行到13,还未执行2,此时B线程也在执行,检查singleton非空,直接使用,就会出错

所如果是JDK1.5以及之后的版本,加上Volatile关键字:

private volatile static Singleton singleton;


这样就可以保证singleton对象每次都是从主内存中读取。

静态内部类单例模式:

public class Singleton{
private Singleton{}
public static Singleton getInstance(){
return SingletonHolder.sInstance;
}
/*
静态内部类
*/
private static class SingletonHolder{
private static final Singleton sInstance = new Singleton();
}
}


优点:只有第一次调用getInstance才会导致sInstance被初始化,第一次调用时候会导致虚拟机加载SingletonHolder类,

这样能保证线程安全,也能保证单例对象唯一,还能延迟单例实例化

枚举单例:

public enum SingletonEnum{
INSTANCE;
}


优点:线程安全,唯一,还能防止反序列化。

破坏单例对象的唯一:

1.反射

2.序列化与反序列化(原因:序列化会通过反射调用无参数的构造方法创建一个新的对象。)

http://www.hollischuang.com/archives/1144
如何防止被序列化?添加一个ReadResolve方法。

public class Singleton implements Serializable{
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;
}

private Object readResolve() {
return singleton;
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: