`
splinter_2
  • 浏览: 58955 次
  • 性别: Icon_minigender_1
  • 来自: 上海
社区版块
存档分类
最新评论

单例模式与双重检测 part2

阅读更多

简单概括你的问题,如果初始化发生在释放锁之前不会有什么问题,如果初始化发生在释放锁之后就有可能有问题。

11 楼 fengsky491 2010-04-26   引用
我理解你的意思,那改成这样:
Java代码 复制代码
  1. if (instance == null) {   //0     
  2.    synchronized (Singleton.class) {// 1        
  3.     if (instance == null) {// 2        
  4.      instance = new Singleton();// 3    
  5.          
  6.       //这里是不是只有instance初始化完整,他才会返回?   
  7.       return instance;// 4   
  8.     }        
  9.   }  
 if (instance == null) {   //0  
    synchronized (Singleton.class) {// 1     
     if (instance == null) {// 2     
      instance = new Singleton();// 3 
       
       //这里是不是只有instance初始化完整,他才会返回?
       return instance;// 4
     }     
   }


是不是就能解决问题?
10 楼 dominic6988 2010-04-26   引用
fengsky491 写道
dominic6988 写道
fengsky491 写道
我就想问下,为什么第三种方式,//3没执行完(也就是没有new完整),它为什么会释放锁?

 

 第三步可以看作一个赋值语句,只不过是调用构造函数初始化在付值语句之后。另外一个线程得到锁后就看到当前的instence已经不是null了就直接返回了,这个时候有可能第一个线程初始化工作做了一半,或者没有做。这样后面的线程得到的对像就会有问题。我感觉是这样的。

 

还有new的时候它为什么不会初始化完整了才,释放锁?

 

照这样理解,我是不是也可以认为第二种,在new的时候,只初始化一半,就释放了锁,其他线程进来不是一样看到的instance也不是null,而照样返回一个不完整的实例?

Java代码 复制代码
  1. public class Singleton {      
  2.  private volatile static Singleton instance = null;      
  3.  private Singleton() {}      
  4.  public static Singleton getInstance() {      
  5.   if (instance == null) {   //0   
  6.    synchronized (Singleton.class) {// 1      
  7.     if (instance == null) {// 2      
  8.      instance = new Singleton();// 3      
  9.     }      
  10.    }   //4   
  11.   }      
  12.   return instance;      
  13.  }      
  14. }    
public class Singleton {   
 private volatile static Singleton instance = null;   
 private Singleton() {}   
 public static Singleton getInstance() {   
  if (instance == null) {   //0
   synchronized (Singleton.class) {// 1   
    if (instance == null) {// 2   
     instance = new Singleton();// 3   
    }   
   }   //4
  }   
  return instance;   
 }   
}  

 看上面的代码如果线程一执行语句3因为JVM编译器的优化工作会在构造方法实例化对像之前从构造方法返回指向该对像的引用。此时并没有执行构造方法。

然后程序执行出4此时开始执行构造方法当执行到一半的时候线程的时间片到期,此时并没有完成,线程二在0处结束等待并开始执行发现instance不为空就返回了。

我这样说你能理解吗?

9 楼 fengsky491 2010-04-26   引用
dominic6988 写道
fengsky491 写道
我就想问下,为什么第三种方式,//3没执行完(也就是没有new完整),它为什么会释放锁?

 

 第三步可以看作一个赋值语句,只不过是调用构造函数初始化在付值语句之后。另外一个线程得到锁后就看到当前的instence已经不是null了就直接返回了,这个时候有可能第一个线程初始化工作做了一半,或者没有做。这样后面的线程得到的对像就会有问题。我感觉是这样的。

 

还有new的时候它为什么不会初始化完整了才,释放锁?

 

照这样理解,我是不是也可以认为第二种,在new的时候,只初始化一半,就释放了锁,其他线程进来不是一样看到的instance也不是null,而照样返回一个不完整的实例?

8 楼 dominic6988 2010-04-26   引用
其实个人认为用单例模式主要还是看所创建的对像是不是有状态的,如果是没有状态的就是多创建一个也不会对系统照成大的影响,但是如果是有状态的比如连接(本来是一个连接的结果变成了两个)或者计数器之类的所有线程要共享的这样的情况就不用能ThreadLocal这种方式了,这种方式是每个线程都捅有一个对像的副本且不会相互影响的,如果是这种情况就可以用关键字volatile来解决,或者通过静态内部类(第五种)的方式保证只加载一次来实现单态。
总之楼主总结的不错。能用的这几种方式都总结出来了。
7 楼 玲cc 2010-04-26   引用
恩,楼上说的没错
是因为这样
6 楼 dominic6988 2010-04-26   引用
fengsky491 写道
我就想问下,为什么第三种方式,//3没执行完(也就是没有new完整),它为什么会释放锁?

 

 第三步可以看作一个赋值语句,只不过是调用构造函数初始化在付值语句之后。另外一个线程得到锁后就看到当前的instence已经不是null了就直接返回了,这个时候有可能第一个线程初始化工作做了一半,或者没有做。这样后面的线程得到的对像就会有问题。我感觉是这样的。

5 楼 fengsky491 2010-04-26   引用
我就想问下,为什么第三种方式,//3没执行完(也就是没有new完整),它为什么会释放锁?
4 楼 dominic6988 2010-04-26   引用
另外一个问题是如果用了关键字volatile就能解决双重检测的问题吗?
这样的写法是能避免无序写入的问题。因为别的线程进入不了方法体,除非当前线程释放锁。这样就能确保实例化完成。我的理解对吗?
public class Singleton {  
private volatile static Singleton instance = null;  
private Singleton() {}  
public static Singleton getInstance() {  
 
   synchronized (Singleton.class) {
    if (instance == null) {         
     instance = new Singleton();    
    }  
   }  
 
  return instance;  
}  

3 楼 dominic6988 2010-04-26   引用
谢谢楼主的回复。
正如你所说的用ThreadLocal能解决这个问题,担是我认为你的代码里面的写法是不是有问题。
public class Singleton {
private static final ThreadLocal perThreadInstance = new ThreadLocal();
private static Singleton singleton ;
private Singleton() {}

public static Singleton  getInstance() {
  if (perThreadInstance.get() == null){
   // 每个线程第一次都会调用
   createInstance();
  }
  return singleton;
}

private static  final void createInstance() {
  synchronized (Singleton.class) {
   if (singleton == null){
    singleton = new Singleton();
   }
  }
  perThreadInstance.set(perThreadInstance);
}
}

倒数第三行perThreadInstance.set(perThreadInstance);应该写成perThreadInstance.set(singleton);


除此之外每一个线程都会有一个singleton的副本这样一样会造成资源浪费。本来单态模式就是想节省资源的,这样与模式的初衷不相符吧。

还有这种ThreadLocal方式的解决方案能不能应用在分布式情形,不同的JVM,ClassLoader?
2 楼 junJZ_2008 2010-04-26   引用
dominic6988 写道
楼主能详细说明第二种加载和第三种的区别吗?
我认为第二种方法同步方法加锁对像是this,而第三种加载方式是同步当前类的类对像。所以单从范围上面来讲只是if (instance == null)这一句的区别。


第二种加锁的对象不是this,其实也是 Singleton.class 锁对象,以前我测试过。为什么说是Singleton.class而不是this呢,最简单的理由就是该方法是静态的,这就很明显了:静态方法是不能访问this的。
其实第二也等同于下在面:
Java代码 复制代码
  1. public class Singleton {   
  2.  private volatile static Singleton instance = null;   
  3.  private Singleton() {}   
  4.  public static Singleton getInstance() {   
  5.   
  6.    synchronized (Singleton.class) {   
  7.     if (instance == null) {   
  8.      instance = new Singleton();   
  9.     }   
  10.    }   
  11.   
  12.   return instance;   
  13.  }   
  14. }  
public class Singleton {
 private volatile static Singleton instance = null;
 private Singleton() {}
 public static Singleton getInstance() {

   synchronized (Singleton.class) {
    if (instance == null) {
     instance = new Singleton();
    }
   }

  return instance;
 }
}


第二种与第三种唯一的区别就是第三种多了“instance == null”的条件,但该条件的检测不是放在同步块中的,正是因为这一点,导致了双重检测失效!
1 楼 dominic6988 2010-04-26   引用
楼主能详细说明第二种加载和第三种的区别吗?
我认为第二种方法同步方法加锁对像是this,而第三种加载方式是同步当前类的类对像。所以单从范围上面来讲只是if (instance == null)这一句的区别。
分享到:
评论

相关推荐

    设计模式demo (单例模式、建造者模式、策略模式)

    本示例包含三个经典的设计模式:单例模式、建造者模式和策略模式,它们都是面向对象设计的重要组成部分,尤其在C#编程中广泛应用。 ### 单例模式 单例模式确保一个类只有一个实例,并提供一个全局访问点。这种模式...

    JNDI连接池+单例模式+文件上传

    实现单例模式的方法有很多,如懒汉式、饿汉式、双重检查锁定等。以下是一个简单的双重检查锁定实现: ```java public class DataSourceSingleton { private static volatile DataSource instance; private ...

    iphone 单例模式SynthesizeSingleton.h

    iphone 单例模式// Permission is given to use this source code file without charge in any // project, commercial or otherwise, entirely at your risk, with the condition // that any redistribution (in ...

    java与模式 阎宏 设计模式 part2

    设计模式 书中模式的例子都是基于java的 全书深入浅出 不仅讲明白了常用常用的设计模式...由于最多上传15M,全书分为3个part传输,将part1、part2、part3放在同一个文件夹中,同时选中,选择解压到当前目录即可。part2.

    Java与模式.part01-03.rar

    《Java与模式》是一部深入探讨Java编程语言与设计模式结合应用的著作,旨在帮助开发者提升软件设计能力,更好地理解和实践面向对象设计原则。这个压缩包包含的部分可能为书中的部分内容或者是一系列相关教程的章节,...

    设计模式中文版part2

    在这个"设计模式中文版part2"中,我们继续深入探讨Java编程语言中的设计模式。 1. **单例模式** (Singleton): 单例模式确保一个类只有一个实例,并提供全局访问点。在Java中,通常通过私有构造函数和静态工厂方法...

    Java与模式.part2

    Java与模式.part2 Java与模式.part2 Java与模式.part2

    Java与模式.part19-21.rar

    《Java与模式》系列教程是深入理解Java编程和设计模式的重要资源,这部分涵盖了第...对于压缩包中的"Java与模式.part19-21"文件,建议按照章节顺序逐步学习,结合实际案例进行实践,以确保对每一个主题都有深入的理解。

    《设计模式》中文版part2

    《设计模式》中文版part2是一本深入探讨软件设计原则和最佳实践的书籍,它将经验丰富的程序员在解决常见问题时所采用的方法整理为可复用的解决方案。这本书的第二部分可能涵盖了23种经典的GoF设计模式,以及其他一些...

    研磨设计模式(完整带书签).part2.pdf

    本电子书一共两个压缩文档,本文件为part2. 《研磨设计模式》完整覆盖GoF讲述的23个设计模式并加以细细研磨。初级内容从基本讲起,包括每个模式的定义、功能、思路、结构、基本实现、运行调用顺序、基本应用示例等,...

    敏捷软件开发:原则、模式与实践.part2.rar

    敏捷软件开发:原则、模式与实践.part2.rar 还有part1,别忘了下载哦.

    Java与模式(清晰书签版) 设计模式 part3

    第1章 模式的简史和形而上学 第2章 统一建模语言UML简介 第3章 软件的可维护性和可复用性 第4章 开闭原则 第5章 专题 JAVA语言的接口 第6章 专题 抽象类 第7章 里氏代换原则 ...第15章 单例模式 第16章 .......

    精通CSS与HTML设计模式.part03.rar

    本书是一部非常实用的CSS 与HTML(XHTML)解决方案手册。书中包含了350 多种可以立即使用的设计模式(涉及文本、背景、边框、图片、表格、布局等多方面),并介绍了每种模式的原理... 精通CSS与HTML设计模式.part11.rar

    Java与模式.part07-09.rar

    《Java与模式.part07-09.rar》这个压缩包文件很显然包含了关于Java编程语言和设计模式的深入探讨。这部分内容可能源自一本名为《Java与模式》的书籍或者是一系列教程材料。从文件名来看,它可能是该资料的第七到第九...

    《设计模式》中文版part1

    《设计模式》中文版part1是一本深入探讨软件设计模式的重要资源,对于提升开发者的设计能力和代码质量具有极大的价值。设计模式是经验丰富的软件开发人员在解决常见问题时所形成的通用解决方案,它们经过了时间和...

    Java与模式.part13-15.rar

    《Java与模式》系列教程是深入理解Java编程语言和设计模式的重要资料,涵盖了从基础到高级的Java技术以及各种常用...因此,对于想要在Java领域深入发展的程序员来说,《Java与模式》.part13-15的学习无疑是必不可少的。

    研磨设计模式.part2

    研磨设计模式.part2 一定要下载5部分

    Java与模式(清晰书签版).part2.rar

    这个压缩包分为多个部分,其中包括"Java与模式(清晰书签版).part2.rar",可能是由于文件大小限制或上传问题被分成了多个部分进行分享。用户在获取到所有部分后,需要将它们合并解压才能得到完整的资料。 设计模式是...

    敏捷软件开发:原则、模式与实践.part2

    敏捷软件开发:原则、模式与实践.part2

    New_Head First设计模式(中文版)Part3(108-end).part01.rar

    Head First设计模式(中文版)Part0(封面_封底_序_前言目录).rar Head First设计模式(中文版)Part1(1-39页).rar Head First设计模式(中文版)Part2(39-107页).rar <br>据反映:上次上传的Part3(108-end).part...

Global site tag (gtag.js) - Google Analytics