手写单例模式
单例模式特征
- 构造方法不对外开发的,一般是 private
- 通过一个静态方法或者枚举返回单例类的对象
- 注意多线程的场景
- 注意单例类对象在反序列化时不会重新创建对象
1. 饿汉 如果应用程序总是创建并使用单例实例或在创建和运行时开销不大 加载类 就加载 对象
class Single {
private Single(){}
private static Single single= new Single();
public static Single getInstance(){
return single;
}
2. 懒汉 如果开销比较大,希望用到时才创建就要考虑延迟实例化 Singleton的初 始化需要某些外部资源(比如网络或存储设备)
class single {
private Single(){}
private static Single single = null;
public static synchroized Single getIntenance(){
// 同步锁粒度太大
if(single == null){
single = new Single();
}
}
return single;
}
}
- 加 synchronized 是线程安全的,但是粒度太大
- 双重检查校验 减小粒度
class Single {
private Single(){}
private volatile static Single single= null;
public static Single getInstance(){
if ( single == null ) {
synchronized (Single.class) {//锁整个对象
if ( single == null ) {
single = new Single();
}
}
}
return single;
}
}
在我们 new 一个对象的时候
- single 实例分配对象
- 调用 Single 构造方法 初始化成员变量
- Single 对象 赋值给 single
但是在汇编语言中 ,这三步会 指令重排,所以没办法保证在 赋值时已经 new了实例对象,会导致双重检查 失败 1.5 之后 多了一个关键字 volatile 禁止指令重排
3.静态内部类 延迟加载 用到 对象才加载
class Single{
private Single(){}
private static class SingleHandler{
private static Single single = new Single();
}
public static Single getInstacne(){
return Single.SingleHandler.single;
}
}
4. 枚举 默认线程安全
public class Single{
private Single(){}
public enum SingleEnum{
singleHandler;
private Single single;
private SingleEnum(){
single = new Single();
}
public Single getSingle(){
return single;
}
}
public static Single getInstance(){
return SingleEnum.singleHandler.getSingle();
}
}