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

转载:单例模式的几种写法(包含双检锁写法)

阅读更多
几个参考地址:
http://www.ibm.com/developerworks/cn/java/j-dcl.html
http://www.iteye.com/topic/537563
http://www.iteye.com/topic/260515
http://www.iteye.com/topic/344876
http://www.iteye.com/topic/60179

关键字: singleton 单例 写法 双锁 线程安全

饿汉式单例类
Java代码

   1. public class Singleton 
   2. { 
   3.     private Singleton(){ 
   4.      
   5.     } 
   6.  
   7.     private static Singleton instance = new Singleton(); 
   8.  
   9.     private static Singleton getInstance(){ 
  10.         return instance; 
  11.     } 
  12. } 

public class Singleton
{
private Singleton(){

}

private static Singleton instance = new Singleton();

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

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

内部类式单例类
Java代码

   1. public class Singleton    
   2. {       
   3.         private Singleton(){    
   4.         
   5.     }    
   6.    
   7.     private class SingletonHoledr(){    
   8.         private static Singleton instance = new Singleton();    
   9.     }    
  10.    
  11.     private static Singleton getInstance(){    
  12.         return SingletonHoledr.instance;    
  13.     }    
  14. }  

public class Singleton  
{     
        private Singleton(){  
      
    }  
 
    private class SingletonHoledr(){  
        private static Singleton instance = new Singleton();  
    }  
 
    private static Singleton getInstance(){  
        return SingletonHoledr.instance;  
    }  
}



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



懒汉式单例类
Java代码

   1. public class Singleton    
   2. {       
   3.     private Singleton(){    
   4.    
   5.     }    
   6.    
   7.     private static Singleton instance;    
   8.     public static Singleton getInstance(){    
   9.         if(instance == null){    
  10.             return instance = new Singleton();    
  11.         }else{    
  12.             return instance;    
  13.         }    
  14.     }    
  15. }   

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都为空,这样就会生成两个实例。解决的办法是同步:

可以同步但是效率不高:
Java代码

   1. public class Singleton    
   2. {       
   3.     private Singleton(){    
   4.    
   5.     }    
   6.    
   7.     private static Singleton instance;    
   8.     public static synchronized Singleton getInstance(){    
   9.         if(instance == null){    
  10.             return instance = new Singleton();    
  11.         }else{    
  12.             return instance;    
  13.         }    
  14.     }    
  15. }   

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的时候,根本不需要线程同步。
于是聪明的人们想出了下面的做法:

双检锁写法:
Java代码

   1. public class Singleton{ 
   2.   private static Singleton single;    //声明静态的单例对象的变量 
   3.   private Singleton(){}    //私有构造方法  
   4.    
   5.   public static Singleton getSingle(){    //外部通过此方法可以获取对象   
   6.     if(single == null){    
   7.         synchronized (Singleton.class) {   //保证了同一时间只能只能有一个对象访问此同步块       
   8.             if(single == null){     
   9.                 single = new Singleton();         
  10.         }    
  11.       } 
  12.     }   
  13.     return single;   //返回创建好的对象  
  14.   } 
  15. } 

public class Singleton{
  private static Singleton single;    //声明静态的单例对象的变量
  private Singleton(){}    //私有构造方法
 
  public static Singleton getSingle(){    //外部通过此方法可以获取对象 
    if(single == null){  
        synchronized (Singleton.class) {   //保证了同一时间只能只能有一个对象访问此同步块     
            if(single == null){   
                single = new Singleton();       
        }  
      }
    } 
    return single;   //返回创建好的对象
  }
}





思路很简单,就是我们只需要同步(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)适用。很显然吧,因为基础类型没有调用构造函数这一步。
分享到:
评论

相关推荐

    java-单例模式几种写法

    单例模式是软件设计模式中的一种,用于控制类的实例化过程,确保一个类只有一个实例,并提供全局访问点。在Java中,实现单例模式有多种方法,每种方法都有其特点和适用场景。以下是对这六种常见单例模式实现方式的...

    Java设计模式之单例模式的七种写法

    Java设计模式之单例模式的七种写法 单例模式是一种常见的设计模式,它确保某个类只有一个实例,而且自行实例化并向整个系统提供这个实例。在计算机系统中,线程池、缓存、日志对象、对话框、打印机的驱动程序对象常...

    unity中涉及的三种单例模式

    在Unity游戏开发中,单例模式是一种常用的编程设计模式,它确保一个类只有一个实例,并提供一个全局访问点。这种模式在处理需要跨场景共享数据的情况时尤其有用,因为Unity的场景切换可能导致对象被销毁,而单例则...

    objective-c单例模式的完整书写方式

    单例模式的实现通常包括以下几个关键步骤: 1. **声明一个类方法**:`+ (instancetype)sharedInstance;` 这个方法返回单例对象,是全局获取单例的主要途径。 2. **私有化初始化方法**:`- (instancetype)init NS_...

    简单了解python单例模式的几种写法

    单例模式是一种常用的软件设计模式,在很多编程语言中都有广泛的应用。在Python中实现单例模式不仅有助于提高代码的可读性和可维护性,还能有效控制资源的使用。本文将详细介绍Python中实现单例模式的三种方法:使用...

    01 设计模式之单例模式.pdf

    在Java语言中,实现单例模式主要有以下几种方式: 1. 饿汉式(Eager Initialization) 饿汉式单例模式在类加载的时候就已经进行了实例化,因此它不需要考虑多线程同步的问题。这种方式在类加载时就完成了初始化,...

    谈一谈iOS单例模式

    单例模式是一种常用的软件设计模式。在它的核心结构中只包含一个被称为单例的特殊类。...2、具体单例模式的几种模式 第一种单例模式 //非线程安全写法 static UserHelper * helper = nil; + (UserH

    angular 服务的单例模式(依赖注入模式下)详解

    需要注意的是,虽然提供了`{providedIn: 'root'}`的方式,但文档中明确说明这个属性并不直接与单例模式有关系,它仅仅是服务提供的一种写法。 在实验中,发现即使服务是懒加载的子模块和组件,当通过`app.module....

    C#设计模式.rar

    以下是根据标题和描述中提到的几种设计模式进行的详细解释: 1. **单例模式**:单例模式确保一个类只有一个实例,并提供全局访问点。这种模式在需要频繁创建和销毁对象,且只允许有一个实例的情况下非常有用,如...

    java技术储备,如何提升自己

    1. 单例模式:了解单例模式的几种写法,包括懒汉式、饿汉式、双重检查锁定式等。 2. JDK 中的设计模式:了解 JDK 中的设计模式,包括 IO 中的装饰模式和设配器模式等。 3. 框架中的设计模式:了解常用的设计模式,...

    2023年最新java面试大全

    【06期】单例模式有几种写法? 【07期】Redis中是如何实现分布式锁的? 【08期】说说Object类下面有几种方法呢? 【09期】说说hashCode() 和 equals() 之间的关系? 【10期】Redis 面试常见问答 【11期】分布式...

    《Java基础入门》复习资料(打印).doc.docx

    17. **单例设计模式**:单例模式确保一个类只有一个实例,并提供一个全局访问点。它通常通过私有构造方法、静态变量和静态工厂方法实现。 在学习Java基础时,理解并掌握这些概念是至关重要的,它们构成了编写高效、...

    春招&秋招面经

    以下是几种实现方式: 1. **懒汉式** ```java public class Singleton { private static Singleton singleton = new Singleton(); private Singleton() {} public static Singleton getSingleton() { ...

    design-cart:ES6 设计模式购物车

    这里我们可能会遇到以下几种常见的设计模式: 1. **单例模式**:购物车在整个应用中应当是唯一的,无论用户在哪个页面,购物车的数据都应保持一致。单例模式确保了购物车对象的全局唯一性,避免了多次实例化导致的...

    java_len.zip_java len

    10. **设计模式**:常见的23种设计模式,如单例模式、工厂模式、观察者模式等,是解决常见问题的成熟解决方案。 11. **注解(Annotation)**:用于提供元数据,增强代码的功能和可读性。 12. **Lambda表达式**:...

    JAVA 面试题

    6. **单例模式的几种写法:** 单例模式保证一个类只有一个实例,并提供一个全局访问点。常见的单例实现方式有饿汉式、懒汉式、枚举类型以及利用双重检查锁定机制等。 7. **web.xml加载顺序:** 在Web应用中,web....

    Android SharedPreferences存储的正确写法

    1. **单例模式**:通过`Context.getSharedPreferences()`获取的SharedPreferences对象是单例的,意味着在整个应用中只会有一个实例。这样确保了数据的一致性,避免了多个副本可能导致的冲突。 2. **编辑器模式**:`...

    C#面试资料,囊括了个大IT公司招聘时的习题

    10. **设计模式**:熟悉常见的设计模式,如单例模式、工厂模式、观察者模式等,以及它们在实际开发中的应用。 11. **数据库操作**:SQL基础,ADO.NET或Entity Framework的使用,以及数据库事务处理。 12. **Web...

Global site tag (gtag.js) - Google Analytics