总结各种常见单例模式的实现及原理

最常见,最简单的饿汉模式,不多说
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;
	}
}

下面是关于单例模式常见的10个面试问题,似乎是国外网站翻译过来的。

引用地址: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中的单例模式什么时候是非单例?





你可能感兴趣的:(单例,设计模式)