【剑指offer Java】面试题2:实现Singleton模式
来源:互联网 发布:程序员用浏览器 编辑:程序博客网 时间:2024/05/17 23:41
题目:设计一个类,我们只能生成该类的一个实例。
//饿汉式public static class Singleton01{ //预先初始化static变量 private final static Singleton01 INSTANCE = new Singleton01(); private Singleton01(){ } public static Singleton01 getInstance(){ return INSTANCE; } }
1.优点:线程安全,因为static类在类加载时只初始化一次,保证线程安全
2.缺点:一来就创建实例化对象,不管后面这个对象用不用的到,所以缺点是若构造的实例很大,而构造完又不用,会导致资源的浪费
//懒汉式,无同步锁public static class Singleton02{ private static Singleton02 instance = null; //私有化构造方法,保证外部类不能通过此构造器来实例化 private Singleton02(){ } //当多线程同时调用getInstance()时,可能创造多个实例对象,并且将多个实例对象赋值给实例变量instance public static Singleton02 getInstance(){ if(instance == null) instance = new Singleton02(); return instance; } }
- 优点:懒汉式只有在用到的时候(即调用getInstance()方法)才创建实例化对象,避免资源浪费
- 缺点:1、若初始化非常耗时时,会造成资源浪费,2、非线程安全,多线程可能赵成多个实例对象被初始化
//懒汉式,同步锁public static class Singleton03{ private static Singleton03 instance = null; private Singleton03(){ } /* * 获得单例对象实例,同步互斥访问实现线程安全 */ public static synchronized Singleton03 getInstance(){ if(instance == null) instance = new Singleton03(); return instance; } }
优点:1、当要使用时才实例化单例,避免资源浪费。2、线程安全
缺点:1、若初始化实例时耗时,则会造成性能降低。2、每次调用getInstance()都获得同步锁,性能消耗(但却无法避免)
针对Singleton03出现的每次调用getInstance()都获得同步锁而出现的性能问题,那么将synchronized关键字放到getInstance()调用函数里面,如下面Singleton04()代码所示。 但随之而来的问题是:多线程下同时调用getInstance(),这时instance都为空,多线程都进入了synchronized块创建实例,就和前面的Singleton03一样了
//懒汉式,试图将同步锁放在判断是否为单例(instance == null)之后public static class Singleton04{ private static Singleton04 instance = null; private Singleton04(){ } public static Singleton04 getInstance(){ if(instance == null){ synchronized (Singleton04.class){ instance = new Singleton04(); } } return instance; } }
为了解决Singleton03()、Singleton04()带来的可能创建多实例对象问题,所以用双重校验锁。 之所以有两个(instance == null)判断是因为考虑了多线程问题(这也是所谓的双重校验锁),当有多个线程同时调用getInstance()的时候,这些线程都能进入第一个if(instance == null)判断,然而只有一个线程能进入第二个if(instance == null)来创建对象。所以,若没有第二个(instance == null)判断,那么多个线程将会创建多个对象。如Singleton05()所示:
//懒汉式,双重校验锁public static class Singleton05{ private volatile static Singleton05 instance = null; private Singleton05(){ } public static Singleton05 getInstance(){ if(instance == null){ synchronized (Singleton05.class){ if(instance == null) instance = new Singleton05(); } } return instance; } }
我们知道,JVM的内存模型中有一个“无序写”(out-of-order writes)机制,而双重校验锁中instance = new Singleton05()中做了两件事: 1、调用构造方法,创建实例化对象。 2、将实例化对象赋值给引用变量instance 因为“无序写”机制,所以步骤1、2可能是乱序的,因此Singleton05中多线程可能因为第一个线程instance = new Singleton05()先赋值了instance,但是实例化对象却没有建立因此下一个线程进入(instance == null)判断时为false,因此直接返回了instance。但是这个instance是没有经过实例化对象赋值而是默认值的,所以是错误的。而这时第一个线程才开始实例化对象,并且把正确的实例化对象赋值给引用instance。 为了解决JVM的“无序写”问题,用临时变量tmp
PS:其实就是两次(instance == null)判断后面需要synchronized同步锁来进行线程互斥
//懒汉式,双重校验锁public static class Singleton06{ private static Singleton06 instance = null; private Singleton06(){ } public static Singleton06 getInstance(){ if(instance == null){ synchronized(Singleton06.class){ Singleton06 tmp = instance; if(tmp == null){ synchronized(Singleton06.class){ tmp = new Singleton06(); } instance = tmp; } } } return instance; } }
//静态方法块只调用一次,省去了if(instance == null)的比较 public static class Singleton07{ private static Singleton07 instance = null; static{ instance = new Singleton07(); } private Singleton07(){ } public static Singleton07 getInstance(){ return instance; } }
使用静态内部类SingletonHolder来实现懒汉式单例,因为JVM中内部类只有在getInstance()方法第一次被调用时才被加载,即实现了懒汉式(lazy).而static内部类只会被加载一次,因此加载过程是线程安全的
//懒汉式,静态内部类实现public static class Singleton08{ private final static class SingletonHolder{ private static final Singleton08 INSTANCE = new Singleton08(); } private Singleton08(){ } public static Singleton08 getInstance(){ return SingletonHolder.INSTANCE; } }
/* * 总的来说,就是要考虑是否是懒汉式单例?是否线程安全?是否性能最好? * 按照代码的逻辑来考虑,就是是否是懒汉式单例【即(instance == null)】? * 然后考虑是否线程安全【即synchronized的使用】? * 最后考虑性能如何【即sychronized关键字使用是在getInstance()还是在 * (instance == null)之中】 */
参考链接:
(http://blog.csdn.net/derrantcm/article/details/45330779)
(http://www.cnblogs.com/coffee/archive/2011/12/05/inside-java-singleton.html#norma)
0 0
- 【剑指offer Java】面试题2:实现Singleton模式
- 剑指offer面试题 java实现版 面试题2 实现Singleton模式
- 剑指Offer:面试题2 实现Singleton模式
- 剑指offer 面试题2 Singleton模式 C++实现
- 剑指offer|面试题2:实现Singleton模式
- 剑指offer-面试题2-实现singleton模式
- 剑指offer面试题2:实现Singleton模式
- 剑指Offer学习之面试题2 : 实现Singleton 模式
- 剑指offer之面试题2:实现Singleton模式
- 剑指offer —面试题2:实现Singleton模式
- 剑指offer面试题2—实现Singleton模式(Java实现)
- 剑指offer面试题2:实现Singleton模式(Java版)
- 剑指offer面试题2:实现Singleton模式(Java版)
- 剑指Offer----面试题二:实现Singleton模式
- 【剑指Offer学习】【面试题2 : 实现Singleton 模式——七种实现方式】
- 剑指Offer之面试题2:实现Singleton
- 【剑指offer】面试题2:实现Singleto模式 java
- <剑指offer 面试题2> 单例模式 (Java实现)
- 滚动条在div或ul等标签中出现
- 5-34 任务调度的合理性 (25分) 拓扑排序
- dztxtrxzjzjvznx
- 浅谈快速排序
- Android--android客户端查询mysql数据库
- 【剑指offer Java】面试题2:实现Singleton模式
- 私人小餐馆发生液化气罐爆
- qekqqocuuauukwe
- BMC
- Eclipse插件springsource-tool-suite的下载和安装
- 跨浏览器鼠标事件写法
- 缓存与数据库一致性保证
- 初识xhprof之安装配置
- STM3日常使用笔记——启动方式