`

单例模式详解

    博客分类:
  • Java
 
阅读更多
//单例模式分为两种:懒汉式和饿汉式,那么接下来分别对这两种的一般写法和谨慎写法代码示例

懒汉式
一般写法
public class Singleton {
	private Singleton(int a){
		System.out.print(a);
	}
	private static Singleton instance=null;
	public static Singleton getinstance(){
		if(instance==null)
		instance=new Singleton(6);
		return instance;
	}

}
但是目前存在两个线程A和B,当A判断完instance为null时,虚拟机把CPU资源判给B,由于instance此时还是为null,所以B执行instance=new Singleton(6),而此时切换到A线程时,A继续执行instance=new Singleton(6),这样就出现了问题。于是
改进写法:
public class Singleton {
	private Singleton(int a){
		System.out.print(a);
	}
	private static Singleton instance=null;
	public static Singleton getinstance(){
		if(instance==null)
			synchronized (Singleton.class) {
				if (instance==null) {
					instance=new Singleton(6);
				}
			}
		
		return instance;
	}
}
这样采用了同步机制又提高效率,但是还是存在一个问题,因为instance=new Singleton(6)是非原子操作(原子操作的意思就是这条语句要么就被执行完,要么就没有被执行过,不能出现执行了一半这种情形),这句代码在编译之后进入虚拟机中执行的对应汇编代码可以发现,有三个步骤,分别为:
1.给Singleton实例分配内存;
2.初始化Singleton构造器;
3.将instance对象指向Singleton实例分配的内存空间(此时instance就为非null了)
在JDK1.5之前,第二步和第三步的顺序是无法保证的,但是在JDK1.5之后,就基本没有问题,所以此种改进写法是一种相对比较完美的写法了





饿汉式
一般写法:
public class Singleton {
	private Singleton(int a){
		System.out.print(a);
	}
	private static Singleton instance = new Singleton(6);
	public static Singleton getinstance() {
		return instance;	
	}
}
但是由于此种写法classloader加载类之后的第一时间就会创建Singleton实例,所以如果这个Singleton实例一些参数需要在getinstance之后通过调用一些配置文件才可以获得,那么就会存在弊端。
改进写法:
public class Singleton {
	private Singleton(int a){
		System.out.print(a);
	}
	private static class SingletonF{
		static final Singleton instance=new Singleton(5);
	}
	public static Singleton getinstance(){
		return SingletonF.instance;
	}
}
这种写法仍能使用JVM机制保证了线程安全,由于SingletonF是私有的,只有getinstance才能访问Singleton实例,因此它是懒汉式的。同时它在取实例的时候不会进行同步,所以没有性能问题,也不依赖于JDK版本。目前来说这种是最优的解决方案。

单例模式的应用场景有数据库的连接,采用数据库连接池,而关闭或者打开数据库连接所引起的效能损耗是非常昂贵的,所以采用单例模式大大降低了这种损耗。
饿死了,中午还没吃饭


分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics