设计模式(1)--单例模式(singleton)

单例模式是面试中问到的最多的模式问题之一。什么是单例,为什么要用单例,单例模式的不合理的实现方法问题,这里就不讨论了。下面将深入学习单例模式的一些理解记录下来(详细的解释我觉得这篇文章写的很好深入浅出单例模式):

1.有一个问题在写单例代码的时候一定要记住,那就是不管什么写法,必须写私有的构造函数,否则你无法真正阻止类被意外的实例化。私有构造函数也防止了继承的存在。

2.synchronized,volatile被抛弃的原因有两个:
其一是效率问题。
其二是synchronized在多线程环境下,由于CPU的指令重排和类装载初始化机制,有可能导致线程一为实例分配了内存并将字面引用指向内存的时候,并没有真正初始化这个类的对象。这个时候如果线程二竞争得到cpu,去判断if(instance==null)会得到false,随后再执行代码时,会得到空指针错误。这时候你就会用到volatile禁止指令重排,但volatile在使用中也可能存在性能问题。

3.private static final Singleton singleton = new Singleton();的问题是你在类装载时就会new了一个对象,但maybe我还不想用他呢?!这时候我们可以用内部类来包装这个变量。这也是要非常注意的一个点:在类装载的时候,内部类并不会同时装载,而是在要使用内部类时才会去装载所以就有了下面的第一种写法。

4.当遇上implements Serializable时,会碰到反序列化时创建的对象又是一个新对象的问题。这个可以简单的使用readresolve方法来解决。
当遇上反射时,问题就麻烦了,有一些攻击手段可以通过反射来调用即使被你声明成private的构造函数。

综上,最主要记住两种写法吧:
第一种,每个地方都很关键,都是坑,需要理解+硬背。

public class Single(){
    private Single(){}//私有构造函数不能少!

    //static的内部类保证了在外部类没有实例化时就可以调用
    //private不能少!保证没有其它类可以调用Holder
    private static class Holder{
        private static final Single INSTANCE = new Single();
    }

    //static保证可以直接调用,final保证了不能被重写
    public static final Single getInstance(){
        return Holder.INSTANCE;
    }
}

第二种写法就牛逼了,使用了枚举Enum。稍微巩固一写枚举知识(枚举自己的用法去学习Enum源码):
1.enum关键字像class关键字一样来修饰类名。这多少有点奇怪,实际上的意思是声明一个类Color,这个Color会继承Enum,是java.lang.Enum的子类。而在写这个Color的时候就必须写出这个Color类有几个实例,如RED,GREEN。 他们默认就是public static final的。
2.枚举类型的默认构造函数就是私有的,自己也只能定义private或者默认级别的构造函数。防止继承和外部不受控制的实例化。
3.枚举虽然实现了Serializable但是在覆盖序列化方法时直接
throw new InvalidObjectException("can't (de)serialize enum"); 表示不能被序列化。
4.在反射类Constructor中的newInstance方法里:

if ((clazz.getModifiers() & Modifier.ENUM) != 0)   
    throw new IllegalArgumentException("Cannot reflectively create enum objects");

即枚举也不支持普通的反射机制。

综上所述枚举是一个极好的单例模式写法:唯一的问题的枚举没办法像使用内部类那样延迟加载。但是时刻要记住:不要用复杂的写法或者实现,去追求不是很明显的性能优化。换句话说,需要合理的而非一味的追求优化。

public enum Singleton{
    INSTANCE //可以有;也可以没有
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值