package singleton.eager; /** * @author donye *类加载时直接初始化,简单明了,但是不用而提前初始化单例,会耗性能 */ public class Singleton { private static Singleton instance = new Singleton(); private Singleton() { } public static Singleton getInstance() { return instance; } }
第二种饿汉模式,在effective java 中提到的利用Enum实现单例模式,可以防止序列化和反射造成的不止一个实例的问题,没看太明白理由?
package singleton.eager; /** * @author donye * */ public enum EnumSingleton { INSTANCE; }
比较有弯弯绕绕的是延迟加载,以下各种 = =!
第一种,直接同步方法
package singleton.lazy; /** * @author donye *直接sync整个方法,很容易明白,同时并发正确。 *但每次访问方法都同步方法會性能,其实我们只需要第一次使用的时候同步就行了 */ public class SyncSingleton { private static SyncSingleton instance= null; private SyncSingleton(){} public static synchronized SyncSingleton getInstance(){ if (instance==null) { return new SyncSingleton(); } return instance; } }
第二种,最复杂的doublecheck,实现同步,网上很多写法是错的,没有考虑jvm所谓的”无序写“的问题,这里有篇博文详细介绍了双检查的原理。
http://www.cnblogs.com/coffee/archive/2011/12/05/inside-java-singleton.html#out-of-orderWrites
但是IBM DEVEOLOPER上也有文章提到了双重检查锁根本无法正确工作……
http://www.ibm.com/developerworks/cn/java/j-dcl.html
有点头大了,后来又google了下,貌似是jdk1.5之后,双重检查锁可以顺利执行了。不用考虑”无序写“问题了。了解为主吧。
package singleton.lazy; /** * @author donye *这是考虑最周全的doublecheck方法,但要明白原理有点复杂,特别是jvm的无序写特点,了解了好吹牛…… */ public class DoubleCheckedSingleton { private static DoubleCheckedSingleton instance= null; private DoubleCheckedSingleton(){} public static DoubleCheckedSingleton getInstance(){ if (instance==null) { synchronized (instance) { DoubleCheckedSingleton temp = instance; if (temp==null) { temp = new DoubleCheckedSingleton(); } instance=temp; } } return instance; } }第三种,最好的一种,用内部类实现延迟加载,解决同步问题。
package singleton.lazy; /** * @author donye *這是懶加載中最棒的方法, *將單例的初始化放入內部類,這樣只有在第一次使用的時候內部類才會加載并初始化成员变量。 *简单实现懒加载,线程同步. */ public class InnerClasSingleton { private static class InstanceHolder{ private static final InnerClasSingleton instance = new InnerClasSingleton(); } private InnerClasSingleton(){} public static InnerClasSingleton getInstance(){ return InstanceHolder.instance; } }
引用地址:http://blog.csdn.net/androidzhaoxiaogang/article/details/6832364
1) 哪些类是单例模式的后续类?在Java中哪些类会成为单例?
这里它们将检查面试者是否有对使用单例模式有足够的使用经验。他是否熟悉单例模式的优点和缺点。
2)你能在Java中编写单例里的getInstance()的代码?
很多面试者都在这里失败。然而如果不能编写出这个代码,那么后续的很多问题都不能被提及。
3)在getInstance()方法上同步有优势还是仅同步必要的块更优优势?你更喜欢哪个方式?
这确实是一个非常好的问题,我几乎每次都会提该问题,用于检查面试者是否会考虑由于锁定带来的性能开销。因为锁定仅仅在创建实例时才有意义,然后其他时候实例仅仅是只读访问的,因此只同步必要的块的性能更优,并且是更好的选择。
4)什么是单例模式的延迟加载或早期加载?你如何实现它?
这是和Java中类加载的载入和性能开销的理解的又一个非常好的问题。我面试过的大部分面试者对此并不熟悉,但是最好理解这个概念。
5) Java平台中的单例模式的实例有哪些?
这是个完全开放的问题,如果你了解JDK中的单例类,请共享给我。
6) 单例模式的两次检查锁是什么?
7)你如何阻止使用clone()方法创建单例实例的另一个实例?
该类型问题有时候会通过如何破坏单例或什么时候Java中的单例模式不是单例来被问及。
8)如果阻止通过使用反射来创建单例类的另一个实例?
开放的问题。在我的理解中,从构造方法中抛出异常可能是一个选项。
9)如果阻止通过使用序列化来创建单例类的另一个实例?
又一个非常好的问题,这需要Java中的序列化知识并需要理解如何使用它来序列化单例类。该问题是开放问题。
10) Java中的单例模式什么时候是非单例?