`

高性能且线程安全的单例

阅读更多
最简单的、成熟的单例实现有如下两种:
1public static final Singleton INSTANCE=new Singleton(); 
即在声明静态变量时就实例化。这种方法的问题是,不能传入构造参数从而动态的创建实例。
2public static synchronized Singleton getInstance(){...} 
即在方法上同步。这种方法的问题是,始终有同步的开销(虽然对很多应用来说这开销并不大,以致不需要考虑),而更理想的情况是,读操作不需要同步,只在创建实例时同步。
3看上去更好的方法(但有问题!)是:
Double-checked synchronization,
private static Singleton INSTANCE;  
public static Singleton getInstance(){  
  if(INSTANCE==null){  
    synchronized(Singelton.class){  
      //Double checking  
      if(INSTANCE==null){  
        INSTANCE=new Singleton();  
      }  
    }  
  }  
}
问题解释如下:
参考1:http://www.ibm.com/developerworks/java/library/j-dcl.html
参考2:http://www.cs.umd.edu/~pugh/java/memoryModel/DoubleCheckedLocking.html
在参考1中提到,out-of-order writes是原因,就是说INSTANCE=new Singleton();这行代码并不是一定按如下伪代码顺序进行的:
1.分配内存
2.调用构造器
3.赋值给INSTANCE

在有的JIT上会编译优化为:
1.分配内存
2.赋值给INSTANCE
3.调用构造器

这就是所谓的out-of-order writes。则问题会出在第2步:此时判断(INSTANCE==null)已经返回真了,但构造器还未调用完成,此时访问INSTANCE则会出现不可预料的问题。
以上都是简单的重复广为人知的知识,下面是我的补充:
在参考2中的"It will work for 32-bit primitive values"一节给了我启发,它提到对32位的原始类型的Double-checked locking是可以的,(我认为实际关键点在于
赋值操作是否是原子的)。既然对int的赋值是原子的,我们可以稍加改进,引入一个int hasInitialized:

private static int hasInitialized=0;  
private static Singleton INSTANCE;  
public static Singleton getInstance(){  
  if(hasInitialized==0){  
    synchronized(Singelton.class){  
      //Double checking  
      if(hasInitialized==0){  
        INSTANCE=new Singleton();  
        hasInitialized=1;  
      }  
    }  
  }  


private static int hasInitialized=0; 
private static Singleton INSTANCE; 
public static synchronized Singleton getInstance(){ 
  if(hasInitialized==0){ 
    synchronized(Singelton.class){ 
      //Double checking 
      if(hasInitialized==0){ 
        INSTANCE=new Singleton(); 
        hasInitialized=1; 
      } 
    } 
  } 

区别在于:
以hasInitialized==0来判断是否初始化完成,而在NSTANCE=new Singleton();之后才赋值以确认初始化完成。
这样不是既可保持高性能(绝大部分情况下没有锁,不进入需同步的块)、又可保证线程安全么?
分享到:
评论

相关推荐

    线程安全的单例模式

    ### 线程安全的单例模式详解 #### 一、单例模式简介 单例模式(Singleton Pattern)是软件开发中最常用的创建型设计模式之一,它的主要目标...其中,双重检查锁定因其较高的性能和线程安全性,成为了较为推荐的做法。

    详解C++实现线程安全的单例模式

    为了使懒汉模式在多线程环境中成为线程安全的单例,我们可以引入互斥锁(`pthread_mutex_t`)。在C++中,通常使用`std::mutex`,但在示例中使用了POSIX线程库`pthread`。当多个线程尝试访问`GetInstance()`时,只有...

    Java中线程安全的单例模式:深入理解与实践

    在实现线程安全的单例模式时,选择哪种方法取决于具体的应用场景。如果应用启动时间不是关键,并且希望尽可能减少内存消耗,可以选择懒汉式;如果应用对性能要求较高,可以选择饿汉式或静态内部类。双重校验锁则适用...

    Java多线程-解决单例模式中的懒汉式的线程安全问题

    ### Java多线程—解决单例模式中的懒汉式的线程安全问题 #### 一、单例设计模式的线程安全问题 ##### (1)饿汉式没有线程安全问题 **饿汉式**是一种非常典型的单例模式实现方式,其特点是在类加载时就完成了实例...

    C++线程安全的单例模式

    在C++编程中,单例模式是一种常用的软件设计模式,它保证了类只有一个实例,并提供一个全局访问点。线程安全的单例模式是当多个线程...而在C++11及更高版本中,内部静态实例的懒汉模式提供了线程安全且高效的解决方案。

    java线程安全总结.doc

    线程安全是指当多个线程访问同一块代码时,如果每个线程都能得到预期的结果,且不产生数据不一致或同步问题,那么这块代码就被称为线程安全的。Java中的线程安全问题通常表现为竞态条件、死锁、活锁和饥饿现象。 ##...

    [代码]在线统计+多线程模拟+单例

    实现单例时通常采用懒汉式(线程不安全)或饿汉式(线程安全),以及双重检查锁定(Double-Checked Locking)等方式,以保证在多线程环境下的正确性。例如: ```java // 懒汉式(线程不安全) public class ...

    Java多线程实战之单例模式与多线程的实例详解

    这种方法可以确保线程安全,但是在高并发情况下,可能会导致性能下降,因为每个线程都需要等待锁的释放。 2. 使用同步代码块 可以使用同步代码块来解决线程安全问题,如下所示: public class MyObject { ...

    host多线程下OpenCL平台等单例

    在OpenCL编程中,"host多线程下OpenCL平台等单例"是一个重要的优化策略,主要用于提升程序的效率和避免资源...这种策略对于大型计算任务或者高性能应用尤其重要,因为它能够最大化利用硬件资源,提高程序的运行效率。

    C++线程安全的单例模式讲解

    当涉及到多线程环境时,线程安全的单例模式变得尤为重要,因为它能防止多个线程同时创建多个实例,导致数据不一致或资源浪费。 1. 懒汉模式(Lazy Initialization) 懒汉模式的特点是延迟初始化,即只有在首次需要...

    几种单例模式demo

    最简单且线程安全的单例实现,JVM保证枚举实例的唯一性。 ```java public enum Singleton { INSTANCE; public void whateverMethod() { //... } } ``` 每种实现方式都有其优缺点,选择哪种方式取决于具体...

    设计模式单例模式

    同步枷锁是通过`synchronized`关键字来实现线程安全的单例模式,但这种方法会降低性能,因为每次调用`getInstance()`方法时都会进行同步: ```java public class Singleton { private static Singleton instance; ...

    多线程精品资源--高并发-高可靠-高性能three-high-import导入系统-高并发多线程进阶.zip

    在IT行业中,多线程是实现高性能和高并发的关键技术之一。"多线程精品资源--高并发-高可靠-高性能three-high-import导入系统-高并发多线程进阶.zip" 这个压缩包文件名暗示了其内容可能包含了一系列关于如何在复杂...

    单例模式各种实现方式

    延迟初始化,只有在第一次调用`getInstance`时才创建单例,但这种方式在多线程环境下不安全。 ```java public class Singleton { private static Singleton instance; private Singleton() {} public static ...

    java单例模式实例

    这是Joshua Bloch在《Effective Java》中推荐的方法,它是最简洁且线程安全的方式。代码如下: ```java public enum Singleton { INSTANCE; public void someMethod() { // 方法实现 } } ``` 总结起来,Java...

    单例模式,属于创建类型的一种常用的软件设计模式 通过单例模式的方法创建的类在当前进程中只有一个实例(根据需要,也有可能一个线程中

    懒汉式—线程不安全:最基础的实现方式,线程上下文单例,不需要共享给所有线程,也不需要加synchronize之类的锁,以提高性能。 懒汉式—线程安全:加上synchronize之类保证线程安全的基础上的懒汉模式,相对性能很...

    Java多线程下的单例模式参考

    在多线程环境中,实现单例模式时需要特别注意线程安全问题,以防止在并发访问时产生多个实例。本篇将探讨如何在Java多线程下实现单例模式,重点关注`synchronized`关键字和`java.util.concurrent.locks.Lock`接口的`...

    Java实现多种单例模式

    在Java编程中,单例模式是一种常用的软件...例如,如果对性能有较高要求,可以考虑饿汉式;如果需要延迟初始化且考虑线程安全,双重校验锁是不错的选择;而在枚举单例中,由于其简洁性和安全性,通常被视为最佳实践。

    设计模式——单例模式(懒汉模式)

    除了DCL之外,还有一种饿汉式单例模式,它在类加载时就完成了实例化,虽然牺牲了懒加载的特性,但提供了更高的效率和线程安全性。不过,对于那些不需要立即加载且生命周期较长的单例对象,懒汉式更加适用。 在实际...

    单例的多种写法和说明比较

    - 非阻塞式单例:线程安全,适用于高并发,性能较好。 在选择单例实现时,需要根据项目需求(如并发量、性能要求、是否允许反射攻击等)进行权衡。在实际应用中,通常推荐使用枚举或静态内部类实现。

Global site tag (gtag.js) - Google Analytics