现在的位置: 首页 > 综合 > 正文

Java 单例模式

2018年03月31日 ⁄ 综合 ⁄ 共 1847字 ⁄ 字号 评论关闭

以前只知道Java中,单例模式有两种方法:

/*
 * 	方法一:
 * 	没有延迟加载,但却最简单
 */
public class Singleton {
	private static final Singleton mInstance = new Singleton();
	
	private Singleton(){}
	public static Singleton getInstance(){
		return mInstance;
	}
}

方法一,也是《模式设计之禅》中写的,最简单省事的方法。

/*
 * 	方法二:
 * 	延迟加载
 */
public class Singleton {
	private static Singleton mInstance = null;
	
	private Singleton(){}
	public synchronized static Singleton getInstance(){
		if(mInstance == null){
			mInstance = new Singleton();
		}
		return mInstance;
	}
}

方法二,是为了延迟初始化mInstance而想出来的方法。

注:在方法上加了syncrhonized关键字。

那么,每次访问该方法,都会进入同步区,降低了访问性能,因为mInstance只在第一次为null,之后就已经有值了。不过,现在代的JVM性能已经很高了,所以,这里的性能损失也就可以忽略。

-------------------------------------------------------分割线------------------------------------------------------------

后来,在网上搜索了下JAVA单例还有没有其它方法,果然,另我汗颜,原来一共有5种,除去我上面讲的2种,下面讲其它3种:

/*
 * 	方法三:
 * 	静态内部类,加载时没有初始化mInstance,因此达到了延迟加载
 */
public class Singleton {
	private static class InternalSingleton{
		private static final Singleton mInstance = new Singleton();
	}
	
	private Singleton(){}
	public static Singleton getInstance(){
		return InternalSingleton.mInstance;
	}
}
/*
 * 	方法四:
 * 	用枚举来实现单例模式
 * 	《effective java》中作者推荐,也是能避免线程同步,
 * 	同时还能避免Java中的反射(即反序列化)导致多个实例
 * 
 * 	只有JDK1.5之后才支持枚举
 * 
 * 	使用方法:Singleton.mInstance.function
 */
public enum Singleton{
	mInstance;  // 默认mInstance = this
	
	public void function(){
		// ......
	}
}
/*
 * 	方法五:(在JAVA内存模型中,线程不安全,知道理论上可行就行了)
 * 	双检索
 * 	初衷:对比方法二,多个线程每次去getInstance时,
 * 	都会进入synchronized状态,哪怕mInstance已经不
 * 	为null,因此降低了性能,所以,将synchronized
 * 	放在第一个if判断之后,再判断一次
 * 
 * 	IBM大神有分析这种情况导致不安全的原因:
 * 	http://www.ibm.com/developerworks/cn/java/j-dcl.html
 */
public class Singleton {
	private static Singleton mInstance = null;
	
	private Singleton(){}
	public static Singleton getInstance(){
		if(mInstance == null){
			synchronized(Singleton.class){
				if(mInstance == null){
					mInstance = new Singleton();
				}
			}
		}
		return mInstance;
	}
}

本篇一共讲了5种方法,除了第5种“双检索”方法,知道就行了,但用的话,还是使用其它4种方法,不过,这里还是要说明点(网上也可以找到):

只有方法4,不但线程安全,同时也能JAVA反射机制,创造出N个单例的实例,不过我也说过,方法4使用的是枚举型,因为,至少要保证JDK1.5之上才行。

如果不讨论反射机制导致的问题,方法1,2,3和4都是可以用的。

因此,大家使用单例模式时,也请注意!

抱歉!评论已关闭.