当前位置:首页 > 开发 > 编程语言 > 多线程 > 正文

单例模式中的多线程分析

发表于: 2013-05-27   作者:bijian1013   来源:转载   浏览:
摘要: 谈到单例模式,我们立马会想到饿汉式和懒汉式加载,所谓饿汉式就是在创建类时就创建好了实例,懒汉式在获取实例时才去创建实例,即延迟加载。 饿汉式: package com.bijian.study; public class Singleton { private Singleton() { } // 注意这是private 只供内部调用 private static

谈到单例模式,我们立马会想到饿汉式和懒汉式加载,所谓饿汉式就是在创建类时就创建好了实例,懒汉式在获取实例时才去创建实例,即延迟加载。

饿汉式:

package com.bijian.study;

public class Singleton {

	private Singleton() {
	}

	// 注意这是private 只供内部调用
	private static Singleton instance = new Singleton();

	// 这里提供了一个供外部访问本class的静态方法,可以直接访问  
	public static Singleton getInstance() {
		return instance;
	}
}

懒汉式:

package com.bijian.study;

public class Singleton {

	private static Singleton instance = null;

	public static synchronized Singleton getInstance() {

		// 这个方法比上面有所改进,不用每次都进行生成对象,只是第一次     
		// 使用时生成实例,提高了效率!
		if (instance == null)
			instance = new Singleton();
		return instance;
	}
}

     上面第二中形式的lazy initialization,也就是说第一次调用时初始Singleton,以后就不用再生成了。

注意到lazy initialization形式中的synchronized,这个synchronized很重要,如果没有synchronized,那么使用getInstance()是有可能得到多个Singleton实例。一般认为第一种形式要更加安全些。

       对于上面的懒汉式方式,从多线程角度来看,Synchronized放到方法上会影响性能。于是我们不难想到将其放到方法里。

package com.bijian.study;

public class Singleton {

	private static Singleton instance = null;
	private static String lock = new String();

	public static Singleton getInstance() {

		// 这个方法比上面有所改进,不用每次都进行生成对象,只是第一次     
		// 使用时生成实例,提高了效率!
		if (instance == null)
			synchronized(lock) {
				instance = new Singleton();
			}
		return instance;
	}
}

我们稍加分析,不难发现,这样会存在线程安全问题,假如线程一刚好执行完if (instance == null)的判断语句(还未加锁),调度至线程二也执行这条判断语句,也是true,也进入了if的语句块中,这样就会产生两个实例,而非单实例了。

此时,我们稍加分析,那还不容易,在锁里面再加一个是否为空的判断,即所谓的double-checked locking (DCL),如下所示:

package com.bijian.study;

public class Singleton {

	private static Singleton instance = null;
	private static String lock = new String();

	public static Singleton getInstance() {

		// 这个方法比上面有所改进,不用每次都进行生成对象,只是第一次     
		// 使用时生成实例,提高了效率!
		if (instance == null)
			synchronized(lock) {
				if (instance == null) {
					instance = new Singleton();
				}
			}
		return instance;
	}
} 

     此时,很多人都会觉得无懈可击了。从多线程角度来看,这样写的单例确实没有问题了,但从Java的类创建原理来看,可能还有问题。从浅显简单的理解来看,就是对象还未完全创建出来,但instance变量已被赋值,此时另一个线程获取实例时,会得到instance,但它的堆空间及相关的方法还未完成时,调用实例方法就会出错。

       啊?还存在这样的问题呀?这可以虚拟机的实现问题,难道还要我考虑?是的,其实稍加改动,就可以避免这样的问题。

       解决办法,加一个局部变量,如下所示:

package com.bijian.study;

public class Singleton {

	private static Singleton instance = null;
	private static String lock = new String();

	public static Singleton getInstance() {

		// 这个方法比上面有所改进,不用每次都进行生成对象,只是第一次     
		// 使用时生成实例,提高了效率!
		if (instance == null)
			synchronized(lock) {
				if (instance == null) {
					Singleton temp = new Singleton();
					instance = temp;
				}
			}
		return instance;
	}
}

 

进一步深入可参考:

Double-checked locking and the Singleton pattern

When is a singleton not a singleton?

单例模式中的多线程分析

  • 0

    开心

    开心

  • 0

    板砖

    板砖

  • 0

    感动

    感动

  • 0

    有用

    有用

  • 0

    疑问

    疑问

  • 0

    难过

    难过

  • 0

    无聊

    无聊

  • 0

    震惊

    震惊

编辑推荐
多线程之 单例设计模式 饿汉式 多线程安全代码: 代码1: /** * 饿汉式 * */ class Single { private
java中的单例模式 HK学习笔记 首先定义一个皇帝 Emperor.java public class Emperor { private stat
Apple官方建议 static MyGizmoClass *sharedGizmoManager = nil;   + (MyGizmoClass*)sharedManag
单例模式是日常开发工作中经常会用到的一种设计模式。通过单例模式,可以保证程序中的一个类只有一
模式的定义 确保某一个类只有一个实例,而且自行实例化并向整个系统提供这个实例。 使用场景 确保某
单例模式(JAVA vs Scala) Singlton是一种为许多人熟知的设计模式,到了Scala这里,它成了语言的一部
单例模式 http://www.ibm.com/developerworks/cn/java/j-dcl.html 定义: Ensure a class has only
iOS多线程技术—单例模式(ARC) 一、简单说明: 设计模式:多年软件开发,总结出来的一套经验、方
在最初学习设计模式时,我为绝佳的设计思想激动不已,在以后的工程中,多次融合设计模式,而在当下
单例模式的特点: 只创建一次 私有的属性 公有的访问方法 单例模式的分类: 懒汉(LazySingleton)
版权所有 IT知识库 CopyRight © 2009-2015 IT知识库 IT610.com , All Rights Reserved. 京ICP备09083238号