最近在看三石-道的关于并发的一些博客,在一篇博客中看到了基于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技术的发展,枚举单例、基于依赖注入的单例等新型实现方式也逐渐流行,它们提供了更好的解决方案,避免了传统单例模式的一些问题。在阅读《浅议单例模式之线程安全.doc》文档时,可以深入理解这些细节...
单例模式是软件设计模式中的一种经典模式,它在许多实际场景中被广泛使用,尤其在需要控制类的实例只有一个的情况下。单例模式确保无论在程序的任何地方,只要通过特定方式请求创建该类的对象,始终只会返回同一个...
Java中实现单例模式的方法有多种,如懒汉式(线程不安全)、饿汉式(静态初始化)、双重检查锁定(DCL)等,其中DCL是推荐的线程安全实现方式。 面向对象(Object-Oriented Programming,OOP)是Java的核心特性,...
单例模式是软件设计模式中的一种,用于控制类的实例化过程,确保一个类在整个程序运行期间只有一个实例存在。这种模式常被用于管理共享资源,如数据库连接、线程池或者配置文件等,以减少系统资源的浪费并提高效率。...
本文将基于提供的文档片段来详细分析ASP.NET中C++单例模式实现的问题及几种可能的解决方案。 #### 问题分析 文档中提到了在多线程环境下实现单例模式时面临的问题——由于静态变量的初始化不是线程安全的,因此...
然后,项目中提到了单例模式,尤其是双检锁/双重校验锁(DCL)。单例模式是一种设计模式,确保一个类只有一个实例,并提供全局访问点。在Java中,考虑到线程安全,DCL是实现线程安全单例的常用方法。它通过双重检查...
例如,单例模式确保一个类只有一个实例,并提供全局访问点,其JAVA实现可能包括懒汉式(线程不安全)、饿汉式(静态常量)和双重检查锁定(DCL)等版本。工厂模式通过一个公共接口创建对象,隐藏了具体类的实例化...
而“singleton method.txt”很可能是讲解或展示了不同类型的单例实现方式,包括传统的单例模式和基于枚举的单例实现。 通过深入学习和实践这三个主题,你将能更好地理解和掌握Java的核心特性,以及在实际项目中如何...
实现Java中的单例模式有多种方法,包括懒汉式(线程不安全)、饿汉式、双重检查锁定(DCL)以及静态内部类等,每种方式都有其优缺点和适用场景。 系统中涉及的管理员功能可能包括了问题的添加、删除、修改以及查询...
1. **单例模式**:保证一个类只有一个实例,并提供一个全局访问点。常见的实现方式有懒汉式(线程不安全)、饿汉式(线程安全)、双重检查锁定(DCL)以及静态内部类等。例如,`SingletonExample.java` 文件可能会...
1. **单例模式** (Singleton): 这是一种限制类实例化次数为一个的模式,常用于全局访问点,例如配置管理或线程池。Java中常见的实现方式包括懒汉式(线程不安全)和饿汉式(线程安全),还有双重检查锁定(DCL)和...
1. **单例模式**:确保一个类只有一个实例,并提供一个全局访问点。在Java中,有饿汉式、懒汉式、双重检查锁定(DCL)和静态内部类四种常见实现方式。通过这种方式,可以避免资源浪费,如数据库连接池。 2. **工厂...
1. **单例模式**:确保一个类只有一个实例,并提供一个全局访问点。在Java中,通常使用双重检查锁定(DCL)或者静态内部类来实现线程安全的单例。 2. **工厂模式**:提供一个创建对象的接口,但让子类决定实例化哪...
设计模式之 Singleton(单态/单件) 阎宏博士讲解:单例(Singleton)模式 保证一个类只有一个实例,并提供一个访问它的全局访问点 设计模式之 Factory(工厂方法和抽象工厂) 使用工厂模式就象使用 new 一样频繁. ...
1. 单例模式:学习如何在Java中实现线程安全的单例,包括懒汉式、饿汉式以及双检锁(DCL)实现。 2. 工厂模式:了解简单工厂、工厂方法和抽象工厂模式,以及它们在不同场景下的应用。 3. 构造器模式:探索如何使用...
- 通常使用单例模式,例如双重检查锁定(DCL)或静态内部类方式,直接设置`maximumPoolSize`为1不是最佳实践。 9. **高并发解决方案** - 可以使用同步机制(如`synchronized`关键字、锁)、线程池、异步处理、...
描述中提到的私有构造函数是单例模式的核心特性,确保类只有一个实例并提供全局访问点。 单例模式是一种常用的面向对象设计模式,它的核心思想是限制类的实例化,只允许存在一个全局共享的实例。在C#中,通常我们...
- **单例模式**:在多线程环境下,确保类只有一个实例,常见的有双重检查锁定(DCL)和静态内部类实现。 - **线程池模式**:`ThreadPoolExecutor`可以视为工厂模式和代理模式的结合,管理线程的创建和销毁,提高...