Double Check形式的单例模式

这两天在看开源项目时,发现Event Bus和Universalimageloader中写单例模式都是Double Check的形式。平时总是看到各种各样的单例模式,如,饿汉式,懒汉式等等。其中大多存在问题。今天记录一种比较优秀的单例模式的写法------Double Check。以后我准备就用这种方法了。(虽然还有其他优秀的方式,比如内部静态类,枚举)

先上代码:

public class ImageLoader {

	private volatile static ImageLoader instance;

	// Returns singleton class instance
	public static ImageLoader getInstance() {
		if (instance == null) {
			synchronized (ImageLoader.class) {
				if (instance == null) {
					instance = new ImageLoader();
				}
			}
		}
		return instance;
	}
}

这是EventBus中的代码。其中两次检查是否instance == null,第一个是为了避免每次都加锁,毕竟这有一定的开销。第二个是为了避免同步问题,比如十个线程同时调用getInstance()方法,都执行了第一步检查instance == null,并且其中一个线程成功获得了锁(执行了synchronized语句),接下来如果没有再一次判断instance == null,则十个线程将生成10对象,这违背了单例的初衷。

上述代码除了有两次检查instance == null,另一个特点是变量instance的类型声明中添加了volatile,因为像下面这种创建对象的语句并不是原子操作,volatile可以使其成为原子操作,避免同步问题。

instance = new ImageLoader();

虽说部分JVM没有完全volatile,但是目前主流的JVM貌似已经都支持了,所以这个问题一般可以忽略。

参考:

http://www.zhihu.com/question/29971746

https://www.v2ex.com/t/193589#reply15

时间: 2024-11-10 01:19:53

Double Check形式的单例模式的相关文章

单例模式的两种实现方式对比:DCL (double check idiom)双重检查 和 lazy initialization holder class(静态内部类)

首先这两种方式都是延迟初始化机制,就是当要用到的时候再去初始化. 但是Effective Java书中说过:除非绝对必要,否则就不要这么做. 1. DCL (double checked locking)双重检查: 如果出于性能的考虑而需要对实例域(注意这个属性并没有被static修饰)使用延迟初始化,就使用双重检查模式 public class Singleton { private volatile Singleton uniqueInstance; private Singleton(){

多线程下的单例-double check

话不多说直接上代码: public sealed class Singleton { private static Singleton _instance = null; // Creates an syn object. private static readonly object SynObject = new object(); Singleton() { } public static Singleton Instance { get { // Double-Checked Lockin

【C++设计模式】单件类与DCLP(Double Check Lock Pattern)的风险

[单件类] 保证只能有一个实例化对象,并提供全局的访问入口. [设计注意事项] 1.阻止所有实例化的方法: private 修饰构造函数,赋值构造函数,赋值拷贝函数. 2.定义单实例化对象的方法: a.使用static 修饰 b.使用new+delete的方法 3.多线程版本: 使用双检测锁定,即先检测单实例对象是否存在:不存在,使能"锁",再次判断实例是否存在,不存在就创建该单实例对象. A.单层锁示例: Singleton* Singleton::getInstance() { L

java后端研发经典面试题总结

垃圾回收算法 1.标记-清除算法 标记-清除算法是最基本的算法,和他的名字一样,分为两个步骤,一个步骤是标记需要回收的对象.在标记完成后统一回收被标记的对象.这个算法两个问题.一个是效率问题,标记和清除的效率不高.第二个问题是标记-清除之后会有大量不连续的碎片空间,如果我们需要更大的连续内存就必须GC. 2.复制算法 复制算法,不同于标记-清除,复制算法大多数用于新生代,它需要大小相等的两块内存,每次只使用一块内存,当GC的时候会把这块内存存活的对象复制到另外一块内存上面,解决了时间效率和空间碎

Java 8 并发编程

Java 1.5前 并发实现 Java Green Thread java 1.2 前的线程受os内核限制, 线程=进程, 绿色线程是JVM调度, 用来模拟多线程环境. 不需要本地线程支持. Java Native Thread 对比 绿色线程在线程激活和线程同步方面优于本地线程 在I/O和上下文操作方面性能要低于本地线程 编程模型 Thread Runnable 局限性(后续版本将解决完善这部分缺陷, 可对比学习) 缺少线程管理的原生支持(缺少线程池) 缺少"锁"API(只有 syn

iOS-地图真实坐标表示形式之间转换(double型,int型 互转)

在开发中可能会遇到这种需求,前端获取的地理坐标并不能在后台以double的形式表示,需要将其转化为其他样式比如:XX度XX分XX秒 的形式表示 进而转化为秒的形式即整形的形式 封装了两个类可直接实现地图经纬度坐标真实和整形表示方法的转换方式: /** 如何将度(DDD):: 108.90593度换算成度分秒(DMS)东经E 108度54分22.2秒?转换方法是将108.90593整数位不变取108(度),用0.90593*60=54.3558,取整数位54(分),0.3558*60=21.348

从jvm的角度来看单例模式

最近在看jvm,发现随着自己对jvm底层的了解,现在对java代码可以说是有了全新的认识.今天就从jvm的角度来看一看以前自以为很了解的单例模式. 了解单例模式的人都知道,单例模式有两种:"饿汉模式"和"懒汉模式". 引用一段网上对这两种模式的介绍: "饿汉模式的特点是加载类时比较慢,但运行时获取对象的速度比较快,线程安全.饿汉式是线程安全的,在类创建的同时就已经创建好一个静态的对象供系统使用,以后不在改变.懒汉模式的特点是加载类时比较快,但是在运行时获取

"围观"设计模式(7)--创建型之单例模式(Singleton Pattern)

单例模式,也叫单子模式,是一种常用的软件设计模式.在应用这个模式时,单例对象的类必须保证只有一个实例存在.许多时候整个系统只需要拥有一个的全局对象,这样有利于我们协调系统整体的行为.比如在某个服务器程序中,该服务器的配置信息存放在一个文件中,这些配置数据由一个单例对象统一读取,然后服务进程中的其他对象再通过这个单例对象获取这些配置信息.这种方式简化了在复杂环境下的配置管理.----维基百科(WIKIPEDIA) 个人的理解: 单例模式概念比较简单,他的目的就是只允许出现一个该类的实例,经常在JD

深入理解单例模式:静态内部类单例原理

本文主要介绍java的单例模式,以及详细剖析静态内部类之所以能够实现单例的原理.OK,废话不多说,进入正文. 首先我们要先了解下单例的四大原则: 1.构造私有. 2.以静态方法或者枚举返回实例. 3.确保实例只有一个,尤其是多线程环境. 4.确保反序列换时不会重新构建对象. 我们常用的单例模式有: 饿汉模式.懒汉模式.双重锁懒汉模式.静态内部类模式.枚举模式,我们来逐一分析下这些模式的区别. 1.饿汉模式: public class SingleTon{ private static Singl