线程安全的单例模式及双重检查锁—个人理解

在web应用中服务器面临的是大量的访问请求,免不了多线程程序,但是有时候,我们希望在多线程应用中的某一个类只能新建一个对象的时候,就会遇到问题。

首先考虑单线程,如果要求只能新建一个对象,那么构造函数我们要设为private。简单的想法:

class singleton{
  private singleton(){
    //.....
  }
  private static singleton instance;
  public static singleton getinstance(){
    if(instance==null)            //1
    instance = new singleton();  //2
    return instance
  }
}

这对于单线程是合理的,第一次调用singleton类时,会新建出singleton对象,但之后访问时,返回的是第一次新建的instance。

但多线程访问时,有可能同时进入//1处的条件判断,多次执行2代码,从而新建多个singleton对象。我们考虑使用同步关键字sycronized

class singleton{
  private singleton(){
    //.....
  }
  private static singleton instance;
  public static singleton synchronized getinstance(){
    if(instance==null)            //1
      instance = new singleton();  //2
    return instance
  }
}

此时可以保证不出错,是单例模式的一种方案,但是问题是每次执行都要用到同步,开销较大。

另外一种想法是,双重检查锁,代码如下:

class singleton{
  private singleton(){
    //.....
  }
  private static singleton instance;
  public static singleton  getinstance(){
    if(instance==null) {           //1
      sycronized(singleton.class){
        if(instance==null)
          instance = new singleton();  //2
       }
    }
    return instance;
  }
}

此写法保证了,当多个进程进入第一个判断锁时,会被同步机制隔离,只有一个程序进入新建对象,再其他线程进入时,instance已经不为null,因此不会新建多个对象。这种方法就叫做双重检查锁,但是也有一个问题,就是java是实行无序写入的机制,在某个线程执行//2代码的过程中,instance被赋予了地址,但是singleton对象还没构造完成时,如果有线程访问了代码//1此时判断instance不为空,但是方法返回的是一个不完整对象的引用。此时可能会产生错误!

另外一种实现单例模式的写法就是

class singleton{
  private singleton(){
    //.....
  }
  private static singleton instance = new singleton();
  public static singleton  getinstance(){
    return instance;
  }
}

这样就不会有之前的问题了。

时间: 2024-12-15 07:27:54

线程安全的单例模式及双重检查锁—个人理解的相关文章

Java单例模式中双重检查锁的问题

单例创建模式是一个通用的编程习语.和多线程一起使用时,必需使用某种类型的同步.在努力创建更有效的代码时,Java 程序员们创建了双重检查锁定习语,将其和单例创建模式一起使用,从而限制同步代码量.然而,由于一些不太常见的 Java 内存模型细节的原因,并不能保证这个双重检查锁定习语有效. 它偶尔会失败,而不是总失败.此外,它失败的原因并不明显,还包含 Java 内存模型的一些隐秘细节.这些事实将导致代码失败,原因是双重检查锁定难于跟踪.在本文余下的部分里,我们将详细介绍双重检查锁定习语,从而理解它

关于并发场景下,通过双重检查锁实现延迟初始化的优化问题隐患的记录

首先,这个问题是从<阿里巴巴Java开发手册>的1.6.12(P31)上面看到的,里面有这样一句话,并列出一种反例代码(以下为仿写,并非与书上一致): 在并发场景下,通过双重检查锁(double-checked locking)实现延迟初始化的优化问题隐患,推荐解决方案中较为简单的一种(适用于JDK5及以上的版本),即目标属性声明为volatile型. 1 public class Singleton { 2 private static Singleton instance=null; 3

单例模式中用volatile和synchronized来满足双重检查锁机制

背景:我们在实现单例模式的时候往往会忽略掉多线程的情况,就是写的代码在单线程的情况下是没问题的,但是一碰到多个线程的时候,由于代码没写好,就会引发很多问题,而且这些问题都是很隐蔽和很难排查的. 例子1:没有volatile修饰的uniqueInstance public class Singleton { private static Singleton uniqueInstance; private Singleton(){ } public static Singleton getInsta

单例模式中 的 双重检查锁 概念与用法

public class Singleton { //私有的 静态的 本类属性 private volatile static Singleton _instance; //私有化构造器 private Singleton() {} /* * 1st version: creates multiple instance if two thread access * this method simultaneouslyX */ public static Singleton getInstance

[杂谈]C++的双重检查锁并不安全

原文地址 http://www.cnblogs.com/hebaichuanyeah/p/6298513.html 一个典型的单例模式构建对象的双重检查锁如下: static Singleton * getSingleObject() { if(singleObject==NULL) { lock(); if(singleObject==NULL) { singleObject = new Singleton(); } unlock(); } return singleObject; } 该代码

C++的双重检查锁并不安全(转)

一个典型的单例模式构建对象的双重检查锁如下: 1 static Singleton * getSingleObject() 2 { 3 if(singleObject==NULL) 4 { 5 lock(); 6 if(singleObject==NULL) 7 { 8 singleObject = new Singleton(); 9 } 10 unlock(); 11 } 12 return singleObject; 13 } 该代码的逻辑是:getSingleObject()函数获得对象

单例陷阱——双重检查锁中的指令重排问题

之前我曾经写过一篇文章<单例模式有8种写法,你知道么?>,其中提到了一种实现单例的方法-双重检查锁,最近在读并发方面的书籍,发现双重检查锁使用不当也并非绝对安全,在这里分享一下. 单例回顾 首先我们回顾一下最简单的单例模式是怎样的? /** *单例模式一:懒汉式(线程安全) */ public class Singleton1 { private static Singleton1 singleton1; private Singleton1() { } public static Singl

从单例的双重检查锁想到的

常说的单例有懒汉跟饿汉两种写法.饿汉由于类加载的时候就创建了对象,因此不存在并发拿到不同对象的问题,但会由于开始就加载了对象,可能会造成一些启动缓慢等性能问题:而懒汉虽然避免了这个问题,但普通的写法会在高并发环境下创建多个对象,单纯加synchronize又会明显降低并发效率,较好的两种写法是静态内部类跟双重检查锁两种. 双重检查锁这个,大家都很熟悉了,上代码: public class SingleTest { private static SingleTest singleTest; //获

双重检查锁实现单例模式的线程安全问题

一.结论 双重校验锁的单例模式代码如下: public class Singleton { private static Singleton singleton; private Singleton() {} public static Singleton getSingleton() { if (singleton == null) { // 1 synchronized (Singleton.class) { // 2 if (singleton == null) { // 3 single