`
notadoor
  • 浏览: 13730 次
  • 性别: Icon_minigender_1
  • 来自: 北京
文章分类
社区版块
存档分类
最新评论

单例模式singleton及双检锁double-checked locking

阅读更多
饿汉式单例类
public class Singleton
{
	private Singleton(){
	
	}

	private static Singleton instance = new Singleton();

	private static Singleton getInstance(){
		return instance;
	}
}

饿汉式提前实例化,没有懒汉式中多线程问题,但不管我们是不是调用getInstance()都会存在一个实例在内存中

内部类式单例类
public class Singleton
{	
        private Singleton(){
	
	}

	private class SingletonHoledr(){
		private static Singleton instance = new Singleton();
	}

	private static Singleton getInstance(){
		return SingletonHoledr.instance;
	}
}

内部类式中,实现了延迟加载,只有我们调用了getInstance(),才会创建唯一的实例到内存中.并且也解决了懒汉式中多线程的问题.解决的方式是利用了Classloader的特性.

懒汉式单例类
public class Singleton
{	
	private Singleton(){

	}

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

在懒汉式中,有线程A和B,当线程A运行到第8行时,跳到线程B,当B也运行到8行时,两个线程的instance都为空,这样就会生成两个实例。解决的办法是同步:
public class Singleton
{	
	private Singleton(){

	}

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

这样写程序不会出错,因为整个getInstance是一个整体的"critical section",但就是效率很不好,因为我们的目的其实只是在第一个初始化instance的时候需要locking(加锁),而后面取用instance的时候,根本不需要线程同步。
于是聪明的人们想出了下面的做法:
public class Singleton
{	
	private Singleton(){

	}

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

思路很简单,就是我们只需要同步(synchronize)初始化instance的那部分代码从而使代码既正确又很有效率。
这就是所谓的“双检锁”机制(顾名思义)。
很可惜,这样的写法在很多平台和优化编译器上是错误的。

原因在于:instance = new Singleton()这行代码在不同编译器上的行为是无法预知的。一个优化编译器可以合法地如下实现instance = new Singleton():

1. instance  = 给新的实体分配内存

2. 调用Singleton的构造函数来初始化instance的成员变量

现在想象一下有线程A和B在调用getInstance,线程A先进入,在执行到步骤1的时候被踢出了cpu。然后线程B进入,B看到的是instance  已经不是null了(内存已经分配),于是它开始放心地使用instance,但这个是错误的,因为在这一时刻,instance的成员变量还都是缺省值,A还没有来得及执行步骤2来完成instance的初始化。

当然编译器也可以这样实现:

1. temp = 分配内存

2. 调用temp的构造函数

3. instance = temp

如果编译器的行为是这样的话我们似乎就没有问题了,但事实却不是那么简单,因为我们无法知道某个编译器具体是怎么做的,因为在Java的memory model里对这个问题没有定义。

双检锁对于基础类型(比如int)适用。很显然吧,因为基础类型没有调用构造函数这一步。
分享到:
评论
2 楼 xiayh04 2013-11-25  
static 里,可以用 this?
1 楼 justdo2008 2009-10-30  
双检锁这里

synchronized(this){  
                if(instance == null)  
                    return instance = new Singleton();  
            }  

是否缺少一个else呢?

相关推荐

    C++ and the Perils of Double Checked Locking.zip

    《C++ and the Perils of Double Checked Locking》是一篇探讨C++编程中双重检查锁定(Double-Checked Locking)模式潜在问题的文献。在多线程编程中,双重检查锁定是一种常见的优化策略,旨在减少对同步原语的依赖...

    单例模式(singleton)

    3. 双重检查锁定(Double-Checked Locking):结合了前两者,延迟初始化并保证线程安全。 ```java public class Singleton { private volatile static Singleton instance; private Singleton() {} public static...

    设计模式C++学习之单例模式(Singleton)

    为了解决这个问题,可以采用双重检查锁定(Double-Checked Locking)的策略: ```cpp class Singleton { private: Singleton() {} static Singleton* instance; static std::mutex mtx; public: static ...

    设计之模式之单例(Singleton)

    这种方式在Java中需要注意线程安全问题,例如双重检查锁定(Double-Checked Locking)。 - **饿汉式**:类加载时就立即创建实例,保证线程安全,但可能会浪费内存。 - **静态内部类**:利用Java类加载机制保证线程...

    单例模式和工厂模式代码

    // 双检锁/双重校验锁(DCL,即 double-checked locking) public class Singleton { private volatile static Singleton instance; private Singleton() {} public static Singleton getInstance() { if ...

    设计模式——单例模式

    1. **双检锁/双重校验锁(DCL,即 double-checked locking)** ```java public class Singleton { private volatile static Singleton instance; private Singleton() {} public static Singleton getInstance...

    C#设计模式学习与演变过程-2-单例模式

    3. **双检单例(Double-Checked Locking)**: 双检锁模式试图在保证线程安全的同时减少不必要的同步开销。其核心思想是只有在实例为空时才进行同步操作: ```csharp public class Singleton { private static ...

    深入浅出单例Singleton模式

    在这个版本中,我们进行了双重检查锁定(Double-Checked Locking),先检查`singleton`是否为空,如果为空才进行同步操作。这种优化减少了同步的开销,但仍然保证了线程安全。 4. **静态内部类**: ```java ...

    2.单例模式(Singleton)1

    - DCL双检锁:解决了经典懒汉式的问题,线程安全但代码复杂。 - 静态内部类:利用类装载机制保证单例,线程安全且推荐使用。 **案例小结** 选择单例模式的实现方式应根据实际需求,考虑性能、线程安全和代码简洁性...

    C#版本的单例模式源码

    2. **双检锁/双重校验锁定(Double-Checked Locking,DCL)** 这种方法在早期的.NET框架中被广泛使用,但后来由于.NET内存模型的变化,其线程安全性变得复杂。在.NET 4.0及更高版本中,可以安全地使用此方法: ``...

    设计模式单例模式

    懒汉式的常见实现是使用双重检查锁定(Double-Checked Locking,DCL): ```java public class Singleton { private volatile static Singleton instance; private Singleton() {} public static Singleton ...

    使用单例模式创建学生管理系统(饿汉式、懒汉式)

    但是,如果不进行同步控制,懒汉式在多线程环境下可能会创建多个实例,因此通常采用双重检查锁定(Double-Checked Locking,DCL)来实现线程安全的懒汉式单例: ```java public class Singleton { private ...

    Singleton 单例模式的介绍以及解析

    2. **双重检查锁定(DCL,Double-Checked Locking)**:这是一种优化的懒汉式实现,通过添加volatile关键字和synchronized关键字来保证线程安全。在多线程环境下,只有一个线程能执行初始化操作,其他线程会等待初始...

    单例模式讲解说明与实例

    另一个解决方案是使用双重检查锁定机制(Double-Checked Locking)来实现线程安全的单例模式。这种方法可以减少 synchronize 的使用,从而提高系统的性能。 ```java public class Singleton { private volatile ...

    singleton单例模式

    2. **双重检查锁定(Double-Checked Locking)**:这种方法是在多线程环境下保证线程安全的单例。首先检查是否已经实例化,如果未实例化,则同步锁定构造函数,确保只有一个线程可以进入,然后创建实例。这种方式...

    java单例模式完全剖析

    为了解决这个问题,可以使用“双检锁/双重校验锁”(Double-Checked Locking)策略: ```java public class ThreadSafeSingleton { private volatile static ThreadSafeSingleton instance; private ...

    Android Singleton单例模式Demo

    除了静态内部类方式,还有其他实现单例的常见方法,如双重检查锁定(Double-Checked Locking,DCL)和枚举方式。但考虑到Android环境的特殊性,静态内部类的方式更推荐,因为它既简单又高效,同时也避免了线程安全...

    java单例模式在android中的应用

    在Java中,通常通过私有构造器、静态内部类或双重检查锁定(Double-Checked Locking)等方式实现单例。以静态内部类为例,代码可能如下: ```java public class Singleton { private static class SingletonHolder...

    singleTon单例模式的创建

    或者采用双重检查锁定(Double-Checked Locking)的方式: ```java public static SingleTon getInstance() { if (singleTon == null) { synchronized (SingleTon.class) { if (singleTon == null) { singleTon...

    单例模式中声明静态自己类型的指针编译显示未定义处理

    2. **使用双检锁(Double-Checked Locking)**:为了在多线程环境下保证线程安全,可以采用双检锁机制。这避免了每次调用`getInstance()`时都需要加锁,提高了效率。不过,需要注意的是,这种方法在某些旧版本的C++...

Global site tag (gtag.js) - Google Analytics