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

单例模式和双检测的加锁(Double-checked locking and the Singleton pattern)

    博客分类:
  • Java
阅读更多

  单例模式在编程中很常见多个线程使用,必须使用某种类型的同步。为了使你的代码更高效Java程序员在单例模式中使用双重检测锁定来限制并发执行的代码量但是由于Java内存模型一些鲜为人知细节这种双重检查锁定不能保证工作,它会偶尔失败此外,其失败的原因并不明显涉及到Java内存模型内部细节。并且是很难追查的本文的其余部分我们将仔细研究双重检查锁定了解它什么时候就发生了


单例模式的习惯写法

Listing1


 

import java.util.*;
class Singleton
{
  private static Singleton instance;
  private Vector v;
  private boolean inUse;

  private Singleton()
  {
    v = new Vector();
    v.addElement(new Object());
    inUse = true;
  }

  public static Singleton getInstance()
  {
    if (instance == null)          //1
      instance = new Singleton();  //2
    return instance;               //3
  }
}

 

  这个类保证了Singleton实例只能被创建一次,是靠将构造方法的访问权限设为私有的,getInstance()方法只能创建一个Singleton对象。这种设计在单线程中是很好的。但是在多线程环境下,你必须通过加锁机制来保护getInstance()方法,否则会创建出两个不同的实例对象。假设现在有两个不同的线程来访问getInstance()方法,可能会按照下面的顺序来执行:

1.线程1调用getInstance()方法,在1处判断结果为true

2.线程1进入if语句块中,但是在执行2处的代码时,开始阻塞了,被线程2赶超

3.线程2调用getInstance()方法,在1处判断结果也为true

4.线程2进入if语句块中,继续执行2处的代码,创建了一个实例,并让instance变量指向了该对象。

5.线程2返回了Singleton对象在第3行中的代码

6.线程1开始继续执行,从被打断的地方

7.线程1在2处又创建了一个实例对象,并返回

上面导致创建了两个实例对象,而该设计模式的目的是只创建一个实例对象。这个问题可以通过用synchronized修饰方法来解决,如下所示:Listing2

public static synchronized Singleton getInstance()
{
  if (instance == null)          //1
    instance = new Singleton();  //2
  return instance;               //3
}

  代码经过这么改进确实解决了上面的问题。通过代码的仔细分析,会发现,每次调用getInstance()方法,都会进行加锁,这显然是不合理的,除了第一次在创建实例的时候需要锁的保护,后来的调用是不再需要的。锁机制是会影响效率的。

为了提高代码执行的效率,双重检查锁定方法被引入了。它的目的就是为了解决一个问题就是除了第一次需要锁保护外,其它是不需要的。

代码改进如下所示:Listing3

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

Listing3中的代码存在Listing1的同样的问题,多个线程可以同时进入if语句块。例如:当线程1正要创建实例的时候被阻塞了,这时线程2仍然能进入if语句块中,这肯定就会再次创建一个实例出来。因此,我们需要再次去check是否为空。代码如下:Listing4

public static Singleton getInstance()
{
  if (instance == null)
  {
    synchronized(Singleton.class) {  //1
      if (instance == null)          //2
        instance = new Singleton();  //3
    }
  }
  return instance;
}

  在理论上双重检查保证了不会再次创建实例,但是在实际中却不是这样的。原因是在JVM中,被称为“out-of-order  writes”是导致问题的主要原因。

当在执行3处的代码时,可能发生这样的一种情况,还没有初始化完毕,就已经赋给了instance,这时另一个线程判断instance时就不为空了,就会返回一个部分初始化的实例对象。代码做了如下改进:Listing5

public static Singleton getInstance()
{
  if (instance == null)
  {
    synchronized(Singleton.class) {      //1
      Singleton inst = instance;         //2
      if (inst == null)
      {
        synchronized(Singleton.class) {  //3
          inst = new Singleton();        //4
        }
        instance = inst;                 //5
      }
    }
  }
  return instance;
}

  改进的地方就是将构造方法的调用和赋值分开来写,只在调用构造方法中加锁,就是new的时候。后续参见

http://www.ibm.com/developerworks/java/library/j-dcl/index.html

 

 

分享到:
评论

相关推荐

    2 单例模式-MOOC课程内容.pdf

    为了保证线程安全,可以使用双重检查锁定模式(Double-Checked Locking Pattern),确保只有一个实例被创建。但是这要求必须使用关键字volatile修饰静态实例变量,以防止指令重排序导致的问题。单例模式1和单例模式2...

    Singleton Pattern 源码

    单例模式(Singleton Pattern)是软件设计模式中的一种,它保证一个类只有一个实例,并提供一个全局访问点。这种模式在很多场景下非常有用,比如控制资源的唯一性、全局配置对象或者缓存服务等。本篇文章将深入探讨...

    线程安全的单例模式

    单例模式(Singleton Pattern)是软件开发中最常用的创建型设计模式之一,它的主要目标是确保一个类只有一个实例,并提供一个全局访问点。单例模式在很多场景下都非常有用,例如系统配置管理、日志记录等场合,这些...

    adv-java-factory-singleton

    考虑到线程安全,现代Java中通常采用双重检查锁定(Double-Checked Locking)或静态内部类等方式来实现线程安全的单例。 在"adv-java-factory-singleton"项目中,我们可以期待看到如何在Java中实现和应用这些模式的...

    java 多线程单例模式详解

    单例模式(Singleton Pattern)是一种常用的软件设计模式,它确保一个类仅有一个实例,并提供一个全局访问点。这种模式通常用于那些需要频繁实例化然后销毁的对象,或者创建对象需要消耗大量资源的情况,比如读取...

    单例 singleton txt

    单例模式(Singleton Pattern)是一种常用的软件设计模式,属于创建型模式之一。其主要目的是确保一个类只有一个实例,并提供一个全局访问点来访问该实例。这在某些情况下非常有用,比如系统中需要频繁创建后又销毁...

    深入浅出设计模式之单件模式

    - 实现方法:通常使用同步方法或双重检查锁定(Double-Checked Locking)来保证线程安全。 - 优点:延迟实例化,节省资源。 - 缺点:每次获取实例时都要进行同步操作,效率较低。 2. **饿汉式**: - 特点:在类...

    单例 单例模式.txt

    一种解决方案是使用双检锁机制(Double Checked Locking Pattern)来确保线程安全。 5. **资源管理**:单例模式下的对象生命周期往往较长,因此需要注意资源的管理,避免内存泄漏等问题。 #### 五、应用场景 1. **...

    JAVA单例模式应用研究

    #### 五、双重检查锁定(Double-Checked Locking)单例模式 为了解决懒汉式单例模式在多线程环境下的性能问题,可以采用双重检查锁定策略。这种方法只在必要时进行同步,提高了效率。 ```java public class ...

    基于C#的设计模式中的单件模式

    单件模式(Singleton Pattern)是软件设计模式中的一种基础模式,它确保一个类只有一个实例,并提供一个全局访问点。在C#中,单例模式的实现有多种方式,包括懒汉式、饿汉式以及线程安全的实现。下面我们将详细讨论...

    java之 ------ 几种常见的简单设计模式

    - 可以通过双重检查锁定(Double-Checked Locking)优化性能。 **线程安全问题及解决方案** - **问题**:在多线程环境中,若不采取措施,则可能会导致单例模式失效,即生成多个实例。 - **解决方案**: - 使用`...

    23种设计模式说明和代码模板

    首先,单例模式(Singleton Pattern)是设计模式中最简单的一种。它确保一个类只有一个实例,并提供一个全局访问点来获取该实例。单例模式在很多应用场合中都有应用,如在需要进行全局控制,或者共享资源访问时。 ...

    C++完美实现Singleton模式

    为了解决这一问题,可以采用双重检查锁定(Double-Checked Locking)模式来确保线程安全性: ```cpp class Singleton { public: static Singleton* Instance() { if (_instance == nullptr) { lock_guard<mutex>...

    SingletonClass_Demo.zip_DEMO

    在软件设计模式中,单例模式(Singleton Pattern)是一种广泛应用且至关重要的模式。它确保一个类只有一个实例,并提供一个全局访问点,使得任何地方都能方便地获取这个唯一实例。在Delphi应用开发中,正确理解和...

    单件实现范例

    单件模式(Singleton Pattern)是设计模式中的一种结构型模式,它的主要目的是确保一个类只有一个实例,并提供一个全局访问点。这种模式常用于系统中需要频繁创建和销毁的对象,例如日志服务、线程池、数据库连接等...

    设计模式C++ 04-05

    在C++中实现单例,需要注意线程安全问题,可能会使用到静态成员变量、双重检查锁定(Double-Checked Locking)以及C++11的std::call_once和std::once_flag等工具来确保正确性。 第5章可能会讲解“工厂模式”...

    经典设计模式

    单例模式(Singleton Pattern)是设计模式中的一种,其主要意图是限制类的实例化次数,确保一个类只有一个实例,并提供一个全局访问点。这样的设计可以避免过多的实例化导致的资源浪费,特别是在需要全局共享资源...

    设计模式面试专题及答案..docx

    线程安全的单例模式通常通过双重检查锁定(double-checked locking)或枚举实现。例如,`java.lang.Runtime`就是单例模式的实例。 2. 工厂模式(Factory pattern):工厂模式提供了一种创建对象的方式,将对象的...

    C#设计模式(word文档)

    单例模式需要注意线程安全问题,如双重检查锁定(Double-Checked Locking)等实现方式。 - **抽象工厂(Abstract Factory)**:提供一个创建一系列相关或相互依赖对象的接口,而无需指定它们的具体类。 - **建造者...

    C#防止程序多次运行

    标题"防止程序多次运行"涉及到的关键技术是单例模式(Singleton Pattern)和互斥锁(Mutex)。下面我们将深入探讨这两个概念及其在C#中的实现。 **单例模式** 单例模式是一种设计模式,它限制一个类只能有一个实例...

Global site tag (gtag.js) - Google Analytics