最近在看三石-道的关于并发的一些博客,在一篇博客中看到了基于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必须返回之前对象的引用。
相关推荐
饿汉模式、懒汉模式、DCL单例模式、枚举;不同情况下使用不同的单例创建模式
单例模式主要有懒汉式和饿汉式两种实现,饿汉式不会有线程安全的问题,但是提前构造对象占用了一定的资源,如果对内存要求较低的场景可以使用饿汉式实现;懒汉式应使用DCL机制来避免多线程竞争资源的问题,并且懒汉...
深入分析java单例模式什么是单例模式单例模式的常见写法一、饿汉式单例优点缺点示例二、懒汉式单例示例1(普通写法)示例2(synchronized写法)示例3(DCL写法)示例4(内部类写法)三、注册式单例示例1(容器式)示例2(枚举式...
Singleton模式可以相当的复杂,比头五种模式加起来还复杂,譬如涉及到DCL双锁检测(double checked locking)的讨论、涉及到多个类加载器(ClassLoader)协同时、涉及到跨JVM(集群、远程EJB等)时、涉及到单例对象...
一个单例模式的晋级过程(饿汉-懒汉-DCL-IoDH-枚举) 文章目录一个单例模式的晋级过程(饿汉-懒汉-DCL-IoDH-枚举)什么是单例?单例有哪些运用场景?实现1.饿汉式测试优化-final2.懒汉式优化-加锁同步3.DCL双检锁/双重...
懒汉式单例模式的实现方式有三种: * 双重检查锁方式(DCL) 12345678910111213 单例模式: 懒汉式:延迟加载方式 饿汉式:立即加载 面试绝对面的都是懒汉式的问题。 单例模式如果使用不当,就容易引起线程安全问题...
单例模式 一个类只有一个实例,并且可以全局访问使用 应用场景 如账户管理类,数据库操作类等(某个对象频繁被访问使用) 常用方式 饿汉式 懒汉式 同步加锁 DCL双重加锁验证 静态内部类 枚举单例 饿汉式 加载类的...
用VB的Form直接生成DCL对话框程序极其调用的LSP文件 能自动对DCL对话框中的参数进行读取和赋值,并输出 使用步骤: 一、在VB中绘制好表单Form 注意:排列的时候尽量一行的Top坐标相同,这样能保证在同一行 二、将...
分析了用AutoCAD内嵌的AutoLISP与DCL整合的开发过程,通过开发表面结构代号绘制工具的实例,说明了利用DCL和AutoLISP能够编写出人机交互强和功能强大的程序,从而对AutoCAD进行有效的二次开发,提高绘图效率,使AutoCAD...
一个学习DCL对话框编程的好教程,适合于初级学者。
AutoLISP_DCL.AutoLISP_DCL.AutoLISP_DCL.AutoLISP_DCL.AutoLISP_DCL.AutoLISP_DCL.AutoLISP_DCL.AutoLISP_DCL.AutoLISP_DCL.
另外介绍了新手常犯错误分析及应对技巧。第4篇(第22~35章)为visuallisp程序设计应用与整合,主要介绍visual lisp的基本环境、重要函数和程序调试;还介绍了autocad activex对象控制以及visual lisp在e2d、3d、文字...
AutoCAD二次开发之DCL对话框自学教程
dcl常用的一些设计方法 主要是大量的一些实例
`1111111111111111111111111111111111111111111
针对DCL专业课程提供期末报告的模板级样例
本次实验了解DCL语言的GRANT和REVOKE语句对数据库存取权限的控制,学会SQL Server 2000的查询分析器中用DCL语言对数据库存取权限进行设定。 本实验需要2学时。 二、实验内容 1.创建新的数据库用户 2.用GRANT语句对...