`

基于DCL的单例模式的分析

 
阅读更多

        最近在看三石-道的关于并发的一些博客,在一篇博客中看到了基于DCL实现的单例模式:

              http://www.molotang.com/articles/407.html

        于是在并发编程网上又看了两篇博客,以加深对单例模式的理解。

        http://ifeve.com/doublecheckedlocking/

        http://ifeve.com/syn-jmm-pre/

        首先总结一下实现单例模式的几种办法:

 

1:最简单,预先初始化了单例的对象,有一定的内存消耗:

public class Singleton { 
private static final Singleton INSTANCE = new Singleton(); 
private Singleton() { 
} 
public static Singleton getInstance() { 
return INSTANCE; 
} 
}

 

 2:比较常见的,加同步锁:

public class Singleton { 
private static Singleton instance = null; 
private Singleton() { 
} 
public static synchronized Singleton getInstance() { 
if (instance == null) 
instance = new Singleton(); 
return instance; 
} 
}

 

3:DCL式(double checking lock),为了避免取得过期对象而想出来的:

public class Singleton { 
private static volatile Singleton instance = null; 
private Singleton() { 
} 
public static Singleton instance() {
if (instance == null) {
synchronized (Singleton.class) { 
if (instance == null) {
instance = new Singleton(); 
} 
} 
} 
return instance; 
} 
}

    DCL式的会有很多问题,在《Java并发编程实践》一书中的16.2.4一节对其进行了说明:问题可能出来线程可能看到部分创建的对象(存在重排的可能性),打算有时间了写个例子验证一下。

 

4:解决了DCL的缺陷,由Bill Pugh提出:不仅实现了延迟加载而且可以实现同步:

public class Singleton { 
private Singleton() { 
} 
private static class SingletonHolder { 
public static final Singleton INSTANCE = new Singleton(); 
} 
public static Singleton getInstance() { 
return SingletonHolder.INSTANCE; 
} 
}

 

 5:《Effective Java》上推荐的,采用enum:

public enum Singleton { 
  INSTANCE; 
  void show(){System.out.println("Singleton");}
}
 
//客户端调用:
public class Test {
	public static void main(String args[]){
		Singleton.INSTANCE.show();
	}
}

 

      enum和class不同,enum的成员函数和成员变量默认都是public的,而class默认都是private的。

 

6:还可以用线程局部存储来修复DCL,每个线程各自保存一个flag来表示该线程是否执行了同步。

class Foo {
 /** If perThreadInstance.get() returns a non-null value, this thread
	has done synchronization needed to see initialization
	of helper */
	 private final ThreadLocal perThreadInstance = new ThreadLocal();
	 private Helper helper = null;
	 public Helper getHelper() {
		 if (perThreadInstance.get() == null) createHelper();
		 return helper;
	 }
	 private final void createHelper() {
		 synchronized(this) {
			 if (helper == null)
				 helper = new Helper();
		 }
	 // Any non-null value would do as the argument here
		 perThreadInstance.set(perThreadInstance);
	 }
}

   

      但是,如果我们采用序列化/烦序列化的时候,单例可能会产生多个对象。这样单例就失败了。

      当然了,采用enum实现单例的话是不用担心序列化/反序列化的,因为readObject和writeObject两个Serializable接口中的方法对enum是单独处理的。

      如果没有采用enum实现单例,又遇到这个类实现了Seriaalizable接口需要序列化/反序列化的情况也不要担心,只要重写readResolve方法就可以了,在readResolve方法中返回之前对象的引用。

像这样:

public class Singleton implements Serializable { 
private static final Singleton INSTANCE = new Singleton(); 
private Singleton() { 
} 
private Object readResolve() { 
//这个很重要
return INSTANCE; 
} 
public static Singleton getInstance() { 
return INSTANCE; 
} 
}

   当进行反序列化时,  ois.readObject();时内部就是通过反射检查implements Serializable的类有没有readResolve方法,如果有就把readResolve的返回值作为ois.readObject();的返回值. 所以readResolve必须返回之前对象的引用。

分享到:
评论

相关推荐

    Java中的五种实现方法【单例模式】

    同时,随着Java技术的发展,枚举单例、基于依赖注入的单例等新型实现方式也逐渐流行,它们提供了更好的解决方案,避免了传统单例模式的一些问题。在阅读《浅议单例模式之线程安全.doc》文档时,可以深入理解这些细节...

    设计模式之单例模式

    单例模式是软件设计模式中的一种经典模式,它在许多实际场景中被广泛使用,尤其在需要控制类的实例只有一个的情况下。单例模式确保无论在程序的任何地方,只要通过特定方式请求创建该类的对象,始终只会返回同一个...

    Java聊天室 观察者模式和单例模式

    Java中实现单例模式的方法有多种,如懒汉式(线程不安全)、饿汉式(静态初始化)、双重检查锁定(DCL)等,其中DCL是推荐的线程安全实现方式。 面向对象(Object-Oriented Programming,OOP)是Java的核心特性,...

    单例模式讲解案例

    单例模式是软件设计模式中的一种,用于控制类的实例化过程,确保一个类在整个程序运行期间只有一个实例存在。这种模式常被用于管理共享资源,如数据库连接、线程池或者配置文件等,以减少系统资源的浪费并提高效率。...

    asp.net中c++单例实现问题分析__1.docx

    本文将基于提供的文档片段来详细分析ASP.NET中C++单例模式实现的问题及几种可能的解决方案。 #### 问题分析 文档中提到了在多线程环境下实现单例模式时面临的问题——由于静态变量的初始化不是线程安全的,因此...

    基于Java零基础实现《学生成绩管理系统》的简单小项目.zip

    然后,项目中提到了单例模式,尤其是双检锁/双重校验锁(DCL)。单例模式是一种设计模式,确保一个类只有一个实例,并提供全局访问点。在Java中,考虑到线程安全,DCL是实现线程安全单例的常用方法。它通过双重检查...

    《易学设计模式》源码

    例如,单例模式确保一个类只有一个实例,并提供全局访问点,其JAVA实现可能包括懒汉式(线程不安全)、饿汉式(静态常量)和双重检查锁定(DCL)等版本。工厂模式通过一个公共接口创建对象,隐藏了具体类的实例化...

    Java练习reflect,singleton,DomAndSax

    而“singleton method.txt”很可能是讲解或展示了不同类型的单例实现方式,包括传统的单例模式和基于枚举的单例实现。 通过深入学习和实践这三个主题,你将能更好地理解和掌握Java的核心特性,以及在实际项目中如何...

    JAVA知识问答器

    实现Java中的单例模式有多种方法,包括懒汉式(线程不安全)、饿汉式、双重检查锁定(DCL)以及静态内部类等,每种方式都有其优缺点和适用场景。 系统中涉及的管理员功能可能包括了问题的添加、删除、修改以及查询...

    设计模式示例代码

    1. **单例模式**:保证一个类只有一个实例,并提供一个全局访问点。常见的实现方式有懒汉式(线程不安全)、饿汉式(线程安全)、双重检查锁定(DCL)以及静态内部类等。例如,`SingletonExample.java` 文件可能会...

    Head First设计模式 Java源代码

    1. **单例模式** (Singleton): 这是一种限制类实例化次数为一个的模式,常用于全局访问点,例如配置管理或线程池。Java中常见的实现方式包括懒汉式(线程不安全)和饿汉式(线程安全),还有双重检查锁定(DCL)和...

    Java常用设计模式源码

    1. **单例模式**:确保一个类只有一个实例,并提供一个全局访问点。在Java中,有饿汉式、懒汉式、双重检查锁定(DCL)和静态内部类四种常见实现方式。通过这种方式,可以避免资源浪费,如数据库连接池。 2. **工厂...

    设计模式(java)

    1. **单例模式**:确保一个类只有一个实例,并提供一个全局访问点。在Java中,通常使用双重检查锁定(DCL)或者静态内部类来实现线程安全的单例。 2. **工厂模式**:提供一个创建对象的接口,但让子类决定实例化哪...

    二十三种设计模式【PDF版】

    设计模式之 Singleton(单态/单件) 阎宏博士讲解:单例(Singleton)模式 保证一个类只有一个实例,并提供一个访问它的全局访问点 设计模式之 Factory(工厂方法和抽象工厂) 使用工厂模式就象使用 new 一样频繁. ...

    design_model:设计模式的相关学习(基于Java)

    1. 单例模式:学习如何在Java中实现线程安全的单例,包括懒汉式、饿汉式以及双检锁(DCL)实现。 2. 工厂模式:了解简单工厂、工厂方法和抽象工厂模式,以及它们在不同场景下的应用。 3. 构造器模式:探索如何使用...

    美团java视频一面1

    - 通常使用单例模式,例如双重检查锁定(DCL)或静态内部类方式,直接设置`maximumPoolSize`为1不是最佳实践。 9. **高并发解决方案** - 可以使用同步机制(如`synchronized`关键字、锁)、线程池、异步处理、...

    在WPF中以Singleton而不是My Singleton进行思考

    描述中提到的私有构造函数是单例模式的核心特性,确保类只有一个实例并提供全局访问点。 单例模式是一种常用的面向对象设计模式,它的核心思想是限制类的实例化,只允许存在一个全局共享的实例。在C#中,通常我们...

    Java 多线程 设计模式

    - **单例模式**:在多线程环境下,确保类只有一个实例,常见的有双重检查锁定(DCL)和静态内部类实现。 - **线程池模式**:`ThreadPoolExecutor`可以视为工厂模式和代理模式的结合,管理线程的创建和销毁,提高...

Global site tag (gtag.js) - Google Analytics