`
iamxi
  • 浏览: 192170 次
  • 性别: Icon_minigender_1
  • 来自: 杭州
社区版块
存档分类
最新评论

【转】JAVA 单例模式与多线程

    博客分类:
  • Java
 
阅读更多

 

单例模式单例模式是一种常见的设计模式,分三种:懒汉式单例、饿汉式单例、内部类单例、登记式单例几种。

单例模式有一下特点:

    1、单例类只能有一个实例。

    2、单例类必须自己自己创建自己的唯一实例。

    3、单例类必须给所有其他对象提供这一实例。

懒汉模式不是线程安全的,饿汉模式是线程安全的,内部内模式利用Classloader的特,注册表模式是线程安全的同时又提供运行期指定单例。


饿汉式单例类:

 

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

 

内部类式单例类:

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

 

 

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)适用。很显然吧,因为基础类型没有调用构造函数这一步。

 

分享到:
评论
3 楼 793059909 2012-09-09  
懒汉模式不是线程安全的,饿汉模式是线程安全的

看来还是饿汉模式比较保险,就是一点内存么
2 楼 793059909 2012-09-09  
synchronized (Singleton.class) {    //保证了同一时间只能只能有一个对象访问此同步块           
              if(single == null){         
                  single = new Singleton();              
         }

此处 synchronized中加上if判断有什么好处呢?
1 楼 793059909 2012-09-09  
synchronized (Singleton.class) {    //保证了同一时间只能只能有一个对象访问此同步块           
              if(single == null){         
                  single = new Singleton();              
         }

相关推荐

    java单例模式实例

    在Java中,有多种实现单例模式的方法,每种都有其特点和适用场景。接下来,我们将深入探讨这些实现方式。 首先,我们来看**懒汉式(Lazy Initialization)**。这种实现方式是在类被首次请求时才创建单例对象,延迟...

    Java 单例模式.pptx

    - **线程安全问题**:懒汉式单例模式在多线程环境下可能会导致创建多个实例,因此需要采用同步机制保证线程安全,例如使用`synchronized`关键字。 - **静态内部类方式** - **实现**: ```java class Single3 {...

    Java 单例模式 懒汉模式

    Java 单例模式 懒汉模式 //懒汉式 多线程中不可以保证是一个对象

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

    Java多线程实战之单例模式与多线程的实例详解 单例模式是Java多线程编程中最常用的设计模式之一,它的主要作用是确保一个类在应用程序中只有一个实例,并提供一个全局访问点。单例模式有多种实现方式,如饿汉模式、...

    Java 单例模式线程安全问题

    然而,在多线程环境下,单例模式可能会遇到线程安全问题,因为多个线程可能会同时访问同一个实例,从而导致数据不一致和其他问题。 在 Java 中,单例模式的实现可以使用双重检查锁机制、静态内部类和枚举类型等方式...

    Java单例模式设计

    Java单例模式是一种常用的设计模式,它保证一个类只有一个实例,并提供全局访问点。这种模式在需要频繁创建和销毁对象的场景中,或者当对象昂贵时(如数据库连接),能够节省系统资源,提高效率。本篇文章将深入探讨...

    使用Java单例模式实现一个简单的日志记录器.txt

    ### 使用Java单例模式实现一个简单的日志记录器 #### 一、单例模式简介 单例模式是一种常用的软件设计模式,在该模式中,一个类只能创建一个实例,并且提供了一个全局访问点来访问该实例。单例模式的主要优点包括...

    Java单例模式深入理解

    Java单例模式是一种设计模式,它允许在程序中创建唯一一个类实例,通常用于管理共享资源,例如数据库连接、线程池或者配置对象等。单例模式的核心在于限制类的构造函数,确保类只能被初始化一次,从而实现全局唯一的...

    JAVA单例模式的几种实现方法

    ### JAVA单例模式的几种实现方法 #### 一、饿汉式单例类 饿汉式单例类是在类初始化时就已经完成了实例化的操作。这种实现方式简单且线程安全,因为实例化过程是在编译期间完成的,不会受到多线程的影响。 **代码...

    Java单例模式的全面总结

    Java中的单例模式主要分为三种实现方式:懒汉式单例、饿汉式单例和登记式单例。 1. 懒汉式单例(Lazy Initialization) 懒汉式单例的特点是在类被加载时不创建实例,而是在首次调用`getInstance()`方法时才进行实例...

    Java单例模式应用研究.pdf

    ### Java单例模式应用研究 #### 一、单例模式概述 单例模式(Singleton Pattern)作为一种最基本的创建型设计模式,其主要目的是控制一个类的实例化过程,确保在整个应用程序中仅存在一个实例,并且该实例能够被全局...

    Java实现多种单例模式

    在Java编程中,单例模式是一种常用的软件设计模式,它保证一个类只有一个实例,并提供一个全局访问点。这种模式在需要频繁创建和销毁对象的场景中尤其有用,因为它可以节省系统资源并确保对象间的协调一致。以下是...

    java单例模式连接数据库源码

    Java单例模式是一种设计模式,它保证一个类只有一个实例,并提供一个全局访问点。在数据库连接管理中,使用单例模式能有效控制资源,避免频繁创建和关闭数据库连接导致的性能损失和资源浪费。以下是对Java单例模式...

    java单例模式的例子

    Java单例模式是一种常见的设计模式,它在软件工程中用于控制类的实例化过程,确保一个类只有一个实例,并提供一个全局访问点。这种模式在系统资源管理、缓存、日志记录等方面应用广泛。下面我们将深入探讨Java单例...

    浅议单例模式之线程安全(转)

    在多线程环境下,线程安全的单例模式尤为重要,因为如果不正确实现,可能会导致多个线程同时创建多个实例,违反了单例模式的基本原则。 在Java中,单例模式通常有以下几种实现方式: 1. 饿汉式(静态常量): ...

    java单例模式完全剖析

    总之,Java中的单例模式虽然简单,但在多线程、类加载器和序列化等特定场景下需要特别注意,以确保其正确性和安全性。开发者应当根据具体的应用场景选择合适的单例实现方式,以达到最佳的效果。

    java设计模式之单例模式.zip

    这些视频可能涵盖了单例模式的基本概念、实现方式、优缺点、适用场景以及可能遇到的问题,如序列化时如何保持单例、如何在多线程环境下正确实现单例等。观看这些视频,可以更深入地理解并掌握Java中的单例模式,从而...

    多线程单例模式并发访问

    #### 二、多线程与CPU交互机制 在多线程环境中,线程与CPU之间的交互机制非常重要。线程间的资源竞争导致了线程调度的重要性。操作系统通过调度算法来决定哪个线程获得CPU时间片,从而实现多线程程序的高效运行。 -...

Global site tag (gtag.js) - Google Analytics