java被java中的单例模式的窗口退出提示语句怎么写?

&&&&&&&&&&&&&&&&&&
posts - 30,comments - 147,trackbacks - 0
阅读排行榜
评论排行榜
转载出处:
第一种(懒汉,线程不安全):
&1&public&class&Singleton&{&&&2&&&&&private&static&Singleton&&&&3&&&& private&Singleton&(){}&&&&4&&&&&public&static&Singleton&getInstance()&{&&&5&&&&&if&(instance&==&null)&{&&&6&&&&&&&&&instance&=&new&Singleton();&&&7&&&&&}&&&8&&&&&return&&&&9&&&&&}&&<span style="color: #&}&&<span style="color: #&
这种写法lazy loading很明显,但是致命的是在多线程不能正常工作。
第二种(懒汉,线程安全):
&1&public&class&Singleton&{&&&2&&&&&private&static&Singleton&&&&3&&&& private&Singleton&(){}&4&&&&&public&static&synchronized&Singleton&getInstance()&{&&&5&&&&&if&(instance&==&null)&{&&&6&&&&&&&&&instance&=&new&Singleton();&&&7&&&&&}&&&8&&&&&return&&&&9&&&&&}&&<span style="color: #&}&&<span style="color: #&
这种写法能够在多线程中很好的工作,而且看起来它也具备很好的lazy loading,但是,遗憾的是,效率很低,99%情况下不需要同步。第三种(饿汉):
<span style="color: #&public&class&Singleton&{&&<span style="color: #&&&&&private&static&Singleton&instance&=&new&Singleton();&&<span style="color: #&&&& private&Singleton&(){}<span style="color: #&&&&&public&static&Singleton&getInstance()&{&&<span style="color: #&&&&&return&&&<span style="color: #&&&&&}&&<span style="color: #&}&&<span style="color: #&
这种方式基于classloder机制避免了多线程的同步问题,不过,instance在类装载时就实例化,虽然导致类装载的原因有很多种,在单例模式中大多数都是调用getInstance方法,&但是也不能确定有其他的方式(或者其他的静态方法)导致类装载,这时候初始化instance显然没有达到lazy loading的效果。
第四种(饿汉,变种):
&1&public&class&Singleton&{&&&2&&&&&private&Singleton&instance&=&null;&&&3&&&&&static&{&&&4&&&&&instance&=&new&Singleton();&&&5&&&&&}&&&6&&&& private&Singleton&(){}&7&&&&&public&static&Singleton&getInstance()&{&&&8&&&&&return&this.&&&9&&&&&}&&<span style="color: #&}&&<span style="color: #&
表面上看起来差别挺大,其实更第三种方式差不多,都是在类初始化即实例化instance。
第五种(静态内部类):
&1&public&class&Singleton&{&&&2&&&&&private&static&class&SingletonHolder&{&&&3&&&&&private&static&final&Singleton&INSTANCE&=&new&Singleton();&&&4&&&&&}&&&5&&&& private&Singleton&(){}&6&&&&&public&static&final&Singleton&getInstance()&{&&&7&&&&&&&& return&SingletonHolder.INSTANCE;&&&8&&&&&}&&&9&}&&<span style="color: #&
这种方式同样利用了classloder的机制来保证初始化instance时只有一个线程,它跟第三种和第四种方式不同的是(很细微的差别):第三种和第四种方式是只要Singleton类被装载了,那么instance就会被实例化(没有达到lazy loading效果),而这种方式是Singleton类被装载了,instance不一定被初始化。因为SingletonHolder类没有被主动使用,只有显示通过调用getInstance方法时,才会显示装载SingletonHolder类,从而实例化instance。想象一下,如果实例化instance很消耗资源,我想让他延迟加载,另外一方面,我不希望在Singleton类加载时就实例化,因为我不能确保Singleton类还可能在其他的地方被主动使用从而被加载,那么这个时候实例化instance显然是不合适的。这个时候,这种方式相比第三和第四种方式就显得很合理。
第六种(枚举):
<span style="color: #&public&enum&Singleton&{&&<span style="color: #&&&&&INSTANCE;&&<span style="color: #&&&&&public&void&whateverMethod()&{&&<span style="color: #&&&&&}&&<span style="color: #&}&&<span style="color: #&
这种方式是Effective Java作者Josh Bloch 提倡的方式,它不仅能避免多线程同步问题,而且还能防止反序列化重新创建新的对象,可谓是很坚强的壁垒啊,不过,个人认为由于1.5中才加入enum特性,用这种方式写不免让人感觉生疏,在实际工作中,我也很少看见有人这么写过。&
第七种(双重校验锁):
&1&public&class&Singleton&{&&&2&&&&&private&volatile&static&Singleton&&&&3&&&& private&Singleton&(){}&&&&4&&&&&public&static&Singleton&getSingleton()&{&&&5&&&&&if&(singleton&==&null)&{&&&6&&&&&&&&&synchronized&(Singleton.class)&{&&&7&&&&&&&&&if&(singleton&==&null)&{&&&8&&&&&&&&&&&&&singleton&=&new&Singleton();&&&9&&&&&&&&&}&&<span style="color: #&&&&&&&&&}&&<span style="color: #&&&&&}&&<span style="color: #&&&&&return&&&<span style="color: #&&&&&}&&<span style="color: #&}&&<span style="color: #&
这个是第二种方式的升级版,俗称双重检查锁定,详细介绍请查看:
在JDK1.5之后,双重检查锁定才能够正常达到单例效果。
有两个问题需要注意:
&&&& 1、如果单例由不同的类装载器装入,那便有可能存在多个单例类的实例。假定不是远端存取,例如一些servlet容器对每个servlet使用完全不同的类& 装载器,这样的话如果有两个servlet访问一个单例类,它们就都会有各自的实例。
&&&& 2、如果Singleton实现了java.io.Serializable接口,那么这个类的实例就可能被序列化和复原。不管怎样,如果你序列化一个单例类的对象,接下来复原多个那个对象,那你就会有多个单例类的实例。
对第一个问题修复的办法是:
&1&private&static&Class&getClass(String&classname)&&&&&&&2&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&throws&ClassNotFoundException&{&&&&&&3&&&&&&&ClassLoader&classLoader&=&Thread.currentThread().getContextClassLoader();&&&&&&4&&&&&&&&5&&&&&&&if(classLoader&==&null)&&&&&&6&&&&&&&&&&classLoader&=&Singleton.class.getClassLoader();&&&&&&7&&&&&&&&8&&&&&&&return&(classLoader.loadClass(classname));&&&&&&9&&&&}&&&&&<span style="color: #&}&&<span style="color: #&
&对第二个问题修复的办法是:&
&1&public&class&Singleton&implements&java.io.Serializable&{&&&&&&2&&&&public&static&Singleton&INSTANCE&=&new&Singleton();&&&&&&3&&&&&&&&4&&&&protected&Singleton()&{&&&&&&5&&&&&&&&&&6&&&&}&&&&&&7&&&&private&Object&readResolve()&{&&&&&&8&&&&&&&&&&&&&return&INSTANCE;&&&&&&9&&&&&&&}&&&&<span style="color: #&}&&&<span style="color: #&
对我来说,我比较喜欢第三种和第五种方式,简单易懂,而且在JVM层实现了线程安全(如果不是多个类加载器环境),一般的情况下,我会使用第三种方式,只有在要明确实现lazy loading效果时才会使用第五种方式,另外,如果涉及到反序列化创建对象时我会试着使用枚举的方式来实现单例,不过,我一直会保证我的程序是线程安全的,而且我永远不会使用第一种和第二种方式,如果有其他特殊的需求,我可能会使用第七种方式,毕竟,JDK1.5已经没有双重检查锁定的问题了。
========================================================================
&同学总结的很到位:
不过一般来说,第一种不算单例,第四种和第三种就是一种,如果算的话,第五种也可以分开写了。所以说,一般单例都是五种写法。懒汉,恶汉,双重校验锁,枚举和静态内部类。
我很高兴有这样的读者,一起共勉。&
阅读(164594)
&re: Java:单例模式的七种写法
单例和线程安全有关系吗?单例取出一个实例,全局只此一个,多线程下使用,必须加以控制才达到线程安全的目的。所以单例不是线程安全的,单例的设计也不是为线程安全考虑的,所以作者纯属误导读者。&&&&&&
&re: Java:单例模式的七种写法
喜欢第五种,简单安全,不过有点儿乱的是,太多选择了,不知道什么时候该用哪一种!&&&&&&
&re: Java:单例模式的七种写法
好文章&&&&&&
&re: Java:单例模式的七种写法
考试考了,但是什么也不会...&&&&&&
&re: Java:单例模式的七种写法 [未登录]
&#64;工工不懂就虚心点&&&&&&
&re: Java:单例模式的七种写法
看一下java的小程序&&&&&&
&re: Java:单例模式的七种写法 [未登录]
&#64;工工我真是笑了。单例模式被应用在多线程时实在是太多了,作者分析各种单例写法的线程安全,如此有用又受益的分析你居然说误导。&&&&&&
&re: Java:单例模式的七种写法
我一直在用第七种&&&&&&
&re: Java:单例模式的七种写法 [未登录]
&#64;工工希望你写java代码还不足2年,不然真为你感到汗颜。&&&&&&
&re: Java:单例模式的七种写法
不懂不要瞎写&&&&&&
&re: Java:单例模式的七种写法 [未登录]
第四个代码有问题吧&&&&&&
&re: Java:单例模式的七种写法
总结非常好!&&&&&&
&re: Java:单例模式的七种写法
总结的非常好,很到位&&&&&&
&re: Java:单例模式的七种写法
第四种(饿汉,变种):&&&&&&
&re: Java:单例模式的七种写法
第四种(饿汉,变种):没有验证 少了一个static字段&&&&&&
&re: Java:单例模式的七种写法
&#64;工工纯属二笔 啥也不懂&&&&&&
&re: Java:单例模式的七种写法
&#64;工工菜逼,请虚心点&&&&&&
&re: Java:单例模式的七种写法
谢谢博主分享&&&&&&
&re: Java:单例模式的七种写法 [未登录]
&#64;工工自己不明白,就不要哗众取宠。 题注说的线程安全值得是获取该对象的时候的线程安全。 如果没有进行线程安全的处理,多个线程通过单例模式获取对象的时候,有可能获取到多个对象。 如果系统是建立在该类是单例的基础上,将会导致非常严重的后果。&&&&&&
&re: Java:单例模式的七种写法
你这个网页被win10浏览器屏蔽了 被报不安全网页 fuck微软!&&&&&&
&re: Java:单例模式的七种写法 [未登录]
博主写的确实很好,能够在最后指出不同的容器在加载的时候需要指定classloader,在序列化时候指定readResolve。我可以很负责任的说博主写的内容确实要比很多人想象的深很多。能够做到上面两点的,不仅很少同时,很多人都是直接的抄袭。给博主一个赞。&&&&&&
&re: Java:单例模式的七种写法
楼主写的不错,但是有个地方说的不对,static代码块并非在类被加载的时候初始化,这个是个误区,所以第5种方法和第4种方法执行效果是一样的。staitic代码块初始化是在类初始化的时候,参照下面:当创建某个类的新实例时(如通过new或者反射,克隆,反序列化等)当调用某个类的静态方法时当使用某个类或接口的静态字段时当调用Java API中的某些反射方法时,比如类Class中的方法,或者java.lang.reflect中的类的方法时当初始化某个子类时当虚拟机启动某个被标明为启动类的类(即包含main方法的那个类)&&&&&&
&re: Java:单例模式的七种写法
&#64;paganono首先,你说的不正确,static初始化块是类加载到JVM时执行的。非static初始化块({})是像你说的那样,你把概念搞混了。其次,版主的的第四个例子写错了。错误如下:private Singleton instance =
应该加上static修饰。return this.
应该去掉this.。第三个示例和第四个示例的效果是一样一样的。&&&&&&
&re: Java:单例模式的七种写法
网上大神真多,膜拜啊&&&&&&
&re: Java:单例模式的七种写法
&#64;Fly鱼this写不写都可以,没有影响&&&&&&
&re: Java:单例模式的七种写法
&#64;Fly鱼人家没错你错了自己写代码看看就知道了&&&&&&
&re: Java:单例模式的七种写法 [未登录]
&#64;工工你是SB吗&&&&&&
&re: Java:单例模式的七种写法 [未登录]
&#64;lyc&#64;wan&#64;浦云鹤我也是醉了,1.第四种写法,错了,static块去给非static的属性赋值,&#64;wan你确信有自己写代码试过行的通?&#64;浦云鹤 改成static写不写this还一样?&#64;lyc &#64;工工 说的应该是单里内变量的线程安全,博主说的是单例实例化的线程安全,都没有错&&&&&&
&re: Java:单例模式的七种写法
&#64;工工渣渣,不要妄作评论!!&&&&&&
&re: Java:单例模式的七种写法
很好的内容,先干为敬&&&&&&
&re: Java:单例模式的七种写法
请问第五种那两个final可以不要?&&&&&&
&re: Java:单例模式的七种写法
或者说只写一个final&&&&&&单例模式可能是代码最少的模式了,但是少不一定意味着简单,想要用好、用对单例模式,还真得费一番脑筋。本文对Java中常见的单例模式写法做了一个总结,如有错漏之处,恳请读者指正。
顾名思义,饿汉法就是在第一次引用该类的时候就创建对象实例,而不管实际是否需要创建。代码如下:
public class Singleton {
private static Singleton = new Singleton();
private Singleton() {}
public static getSignleton(){
这样做的好处是编写简单,但是无法做到延迟创建对象。但是我们很多时候都希望对象可以尽可能地延迟加载,从而减小负载,所以就需要下面的懒汉法:
单线程写法
这种写法是最简单的,由私有构造器和一个公有静态工厂方法构成,在工厂方法中对singleton进行null判断,如果是null就new一个出来,最后返回singleton对象。这种方法可以实现延时加载,但是有一个致命弱点:线程不安全。如果有两条线程同时调用getSingleton()方法,就有很大可能导致重复创建对象。
public class Singleton {
private static Singleton singleton = null;
private Singleton(){}
public static Singleton getSingleton() {
if(singleton == null) singleton = new Singleton();
考虑线程安全的写法
这种写法考虑了线程安全,将对singleton的null判断以及new的部分使用synchronized进行加锁。同时,对singleton对象使用volatile关键字进行限制,保证其对所有线程的可见性,并且禁止对其进行指令重排序优化。如此即可从语义上保证这种单例模式写法是线程安全的。注意,这里说的是语义上,实际使用中还是存在小坑的,会在后文写到。
public class Singleton {
private static volatile Singleton singleton = null;
private Singleton(){}
public static Singleton getSingleton(){
synchronized (Singleton.class){
if(singleton == null){
singleton = new Singleton();
兼顾线程安全和效率的写法
虽然上面这种写法是可以正确运行的,但是其效率低下,还是无法实际应用。因为每次调用getSingleton()方法,都必须在synchronized这里进行排队,而真正遇到需要new的情况是非常少的。所以,就诞生了第三种写法:
public class Singleton {
private static volatile Singleton singleton = null;
private Singleton(){}
public static Singleton getSingleton(){
if(singleton == null){
synchronized (Singleton.class){
if(singleton == null){
singleton = new Singleton();
这种写法被称为“双重检查锁”,顾名思义,就是在getSingleton()方法中,进行两次null检查。看似多此一举,但实际上却极大提升了并发度,进而提升了性能。为什么可以提高并发度呢?就像上文说的,在单例中new的情况非常少,绝大多数都是可以并行的读操作。因此在加锁前多进行一次null检查就可以减少绝大多数的加锁操作,执行效率提高的目的也就达到了。
那么,这种写法是不是绝对安全呢?前面说了,从语义角度来看,并没有什么问题。但是其实还是有坑。说这个坑之前我们要先来看看volatile这个关键字。其实这个关键字有两层语义。第一层语义相信大家都比较熟悉,就是可见性。可见性指的是在一个线程中对该变量的修改会马上由工作内存(Work Memory)写回主内存(Main Memory),所以会马上反应在其它线程的读取操作中。顺便一提,工作内存和主内存可以近似理解为实际电脑中的高速缓存和主存,工作内存是线程独享的,主存是线程共享的。volatile的第二层语义是禁止指令重排序优化。大家知道我们写的代码(尤其是多线程代码),由于编译器优化,在实际执行的时候可能与我们编写的顺序不同。编译器只保证程序执行结果与源代码相同,却不保证实际指令的顺序与源代码相同。这在单线程看起来没什么问题,然而一旦引入多线程,这种乱序就可能导致严重问题。volatile关键字就可以从语义上解决这个问题。
注意,前面反复提到“从语义上讲是没有问题的”,但是很不幸,禁止指令重排优化这条语义直到jdk1.5以后才能正确工作。此前的JDK中即使将变量声明为volatile也无法完全避免重排序所导致的问题。所以,在jdk1.5版本前,双重检查锁形式的单例模式是无法保证线程安全的。
静态内部类法
那么,有没有一种延时加载,并且能保证线程安全的简单写法呢?我们可以把Singleton实例放到一个静态内部类中,这样就避免了静态实例在Singleton类加载的时候就创建对象,并且由于静态内部类只会被加载一次,所以这种写法也是线程安全的:
public class Singleton {
private static class Holder {
private static Singleton singleton = new Singleton();
private Singleton(){}
public static Singleton getSingleton(){
return Holder.singleton;
但是,上面提到的所有实现方式都有两个共同的缺点:
都需要额外的工作(Serializable、transient、readResolve())来实现序列化,否则每次反序列化一个序列化的对象实例时都会创建一个新的实例。
可能会有人使用反射强行调用我们的私有构造器(如果要避免这种情况,可以修改构造器,让它在创建第二个实例的时候抛异常)。
当然,还有一种更加优雅的方法来实现单例模式,那就是枚举写法:
public enum Singleton {
public String getName(){
public void setName(String name){
this.name =
使用枚举除了线程安全和防止反射强行调用构造器之外,还提供了自动序列化机制,防止反序列化的时候创建新的对象。因此,Effective Java推荐尽可能地使用枚举来实现单例。
这篇文章发出去以后得到许多反馈,这让我受宠若惊,觉得应该再写一点小结。代码没有一劳永逸的写法,只有在特定条件下最合适的写法。在不同的平台、不同的开发环境(尤其是jdk版本)下,自然有不同的最优解(或者说较优解)。
比如枚举,虽然Effective Java中推荐使用,但是在Android平台上却是不被推荐的。在这篇Android Training中明确指出:
Enums often require more than twice as much memory as static constants. You should strictly avoid using enums on Android.
再比如双重检查锁法,不能在jdk1.5之前使用,而在Android平台上使用就比较放心了(一般Android都是jdk1.6以上了,不仅修正了volatile的语义问题,还加入了不少锁优化,使得多线程同步的开销降低不少)。
最后,不管采取何种方案,请时刻牢记单例的三大要点:
序列化与反序列化安全
《Effective Java(第二版)》
《深入理解Java虚拟机——JVM高级特性与最佳实践(第二版)》
阅读(...) 评论()博客分类:
首先要解释一下什么是延迟加载,延迟加载就是等到真真使用的时候才去创建实例,不用时不要去创建。
从速度和反应时间角度来讲,非延迟加载(又称饿汉式)好;从资源利用效率上说,延迟加载(又称懒汉式)好。
下面看看几种常见的单例的设计方式:
第一种:非延迟加载单例类
public class Singleton {
private Singleton() {}
private static final Singleton instance = new Singleton();
public static Singleton getInstance() {
第二种:同步延迟加载
public class Singleton {
private static Singleton instance =
private Singleton() {}
public static synchronized Singleton getInstance() {
if (instance == null) {
instance = new Singleton();
第三种:双重检测同步延迟加载 为处理原版非延迟加载方式瓶颈问题,我们需要对 instance 进行第二次检查,目的是避开过多的同步(因为这里的同步只需在第一次创建实例时才同步,一旦创建成功,以后获取实例时就不需要同获取锁了),但在Java中行不通,因为同步块外面的if (instance == null)可能看到已存在,但不完整的实例。JDK5.0以后版本若instance为volatile则可行:
public class Singleton {
private volatile static Singleton instance =
private Singleton() {}
public static Singleton getInstance() {
if (instance == null) {
synchronized (Singleton.class) {// 1
if (instance == null) {// 2
instance = new Singleton();// 3
双重检测锁定失败的问题并不归咎于 JVM 中的实现 bug,而是归咎于 Java 平台内存模型。内存模型允许所谓的“无序写入”,这也是失败的一个主要原因。
无序写入:为解释该问题,需要重新考察上述清单中的 //3 行。此行代码创建了一个 Singleton 对象并初始化变量 instance 来引用此对象。这行代码的问题是:在 Singleton 构造函数体执行之前,变量 instance 可能成为非 null 的,即赋值语句在对象实例化之前调用,此时别的线程得到的是一个还会初始化的对象,这样会导致系统崩溃。什么?这一说法可能让您始料未及,但事实确实如此。在解释这个现象如何发生前,请先暂时接受这一事实,我们先来考察一下双重检查锁定是如何被破坏的。假设代码执行以下事件序列:
1、线程 1 进入 getInstance() 方法。2、由于 instance 为 null,线程 1 在 //1 处进入 synchronized 块。 3、线程 1 前进到 //3 处,但在构造函数执行之前,使实例成为非 null。 4、线程 1 被线程 2 预占。5、线程 2 检查实例是否为 null。因为实例不为 null,线程 2 将 instance 引用返回给一个构造完整但部分初始化了的 Singleton 对象。 6、线程 2 被线程 1 预占。7、线程 1 通过运行 Singleton 对象的构造函数并将引用返回给它,来完成对该对象的初始化。
为展示此事件的发生情况,假设代码行 instance =new Singleton(); 执行了下列伪代码:mem = allocate();
//为单例对象分配内存空间.instance =
//注意,instance 引用现在是非空,但还未初始化ctorSingleton(instance);
//为单例对象通过instance调用构造函数
这段伪代码不仅是可能的,而且是一些 JIT 编译器上真实发生的。执行的顺序是颠倒的,但鉴于当前的内存模型,这也是允许发生的。JIT 编译器的这一行为使双重检查锁定的问题只不过是一次学术实践而已。
如果真像这篇文章:所说那样的话,1.2或以后的版本就不会有问题了,但这个规则是JMM的规范吗?谁能够确认一下。确实,在JAVA2(以jdk1.2开始)以前对于实例字段是直接在主储区读写的.所以当一个线程对resource进行分配空间,初始化和调用构造方法时,可能在其它线程中分配空间动作可见了,而初始化和调用构造方法还没有完成.
但是从JAVA2以后,JMM发生了根本的改变,分配空间,初始化,调用构造方法只会在线程的工作存储区完成,在没有向主存储区复制赋值时,其它线程绝对不可能见到这个过程.而这个字段复制到主存区的过程,更不会有分配空间后没有初始化或没有调用构造方法的可能.在JAVA中,一切都是按引用的值复制的.向主存储区同步其实就是把线程工作存储区的这个已经构造好的对象有压缩堆地址值COPY给主存储区的那个变量.这个过程对于其它线程,要么是resource为null,要么是完整的对象.绝对不会把一个已经分配空间却没有构造好的对象让其它线程可见.
另一篇详细分析文章:
第四种:使用ThreadLocal修复双重检测
借助于ThreadLocal,将临界资源(需要同步的资源)线程局部化,具体到本例就是将双重检测的第一层检测条件 if (instance == null) 转换为了线程局部范围内来作。这里的ThreadLocal也只是用作标示而已,用来标示每个线程是否已访问过,如果访问过,则不再需要走同步块,这样就提高了一定的效率。但是ThreadLocal在1.4以前的版本都较慢,但这与volatile相比却是安全的。
public class Singleton {
private static final ThreadLocal perThreadInstance = new ThreadLocal();
private static S
private Singleton() {}
public static Singleton
getInstance() {
if (perThreadInstance.get() == null){
// 每个线程第一次都会调用
createInstance();
private static
final void createInstance() {
synchronized (Singleton.class) {
if (singleton == null){
singleton = new Singleton();
perThreadInstance.set(perThreadInstance);
第五种:使用内部类实现延迟加载为了做到真真的延迟加载,双重检测在Java中是行不通的,所以只能借助于另一类的类加载加延迟加载:
public class Singleton {
private Singleton() {}
public static class Holder {
// 这里的私有没有什么意义
/* private */static Singleton instance = new Singleton();
public static Singleton getInstance() {
// 外围类能直接访问内部类(不管是否是静态的)的私有变量
return Holder.
下面是测试单例的框架,采用了类加载器与反射。注,为了测试单便是否为真真的单例,我自己写了一个类加载器,且其父加载器设置为根加载器,这样确保Singleton由MyClassLoader加载,如果不设置为根加载器为父加载器,则默认为系统加载器,则Singleton会由系统加载器去加载,但这样我们无法卸载类加载器,如果加载Singleton的类加载器卸载不掉的话,那么第二次就不能重新加载Singleton的Class了,这样Class不能得加载则最终导致Singleton类中的静态变量重新初始化,这样就无法测试了。下面测试类延迟加载的结果是可行的,同样也可用于其他单例的测试:
public class Singleton {
private Singleton() {}
public static class Holder {
// 这里的私有没有什么意义
/* private */static Singleton instance = new Singleton();
public static Singleton getInstance() {
// 外围类能直接访问内部类(不管是否是静态的)的私有变量
return Holder.
class CreateThread extends Thread {
public CreateThread(ClassLoader cl) {
public void run() {
c = cl.loadClass("Singleton");
// 当两个不同命名空间内的类相互不可见时,可采用反射机制来访问对方实例的属性和方法
Method m = c.getMethod("getInstance", new Class[] {});
// 调用静态方法时,传递的第一个参数为class对象
singleton = m.invoke(c, new Object[] {});
} catch (Exception e) {
e.printStackTrace();
class MyClassLoader extends ClassLoader {
private String loadP
MyClassLoader(ClassLoader cl) {
super(cl);
public void setPath(String path) {
this.loadPath =
protected Class findClass(String className) throws ClassNotFoundException {
FileInputStream fis =
byte[] data =
ByteArrayOutputStream baos =
fis = new FileInputStream(new File(loadPath
+ className.replaceAll("\\.", "\\\\") + ".class"));
baos = new ByteArrayOutputStream();
int tmpByte = 0;
while ((tmpByte = fis.read()) != -1) {
baos.write(tmpByte);
data = baos.toByteArray();
} catch (IOException e) {
throw new ClassNotFoundException("class is not found:" + className,
} finally {
if (fis != null) {
fis.close();
if (fis != null) {
baos.close();
} catch (Exception e) {
e.printStackTrace();
return defineClass(className, data, 0, data.length);
class SingleTest {
public static void main(String[] args) throws Exception {
while (true) {
// 不能让系统加载器直接或间接的成为父加载器
MyClassLoader loader = new MyClassLoader(null);
.setPath("D:\\HW\\XCALLC16B125SPC003_js\\uniportal\\service\\AAA\\bin\\");
CreateThread ct1 = new CreateThread(loader);
CreateThread ct2 = new CreateThread(loader);
ct1.start();
ct2.start();
ct1.join();
ct2.join();
if (ct1.singleton != ct2.singleton) {
System.out.println(ct1.singleton + " " + ct2.singleton);
// System.out.println(ct1.singleton + " " + ct2.singleton);
ct1.singleton =
ct2.singleton =
Thread.yield();
浏览 12383
论坛回复 /
(38 / 22064)
babby52561 写道http://dev.csdn.net/author/axman/4c46d233bd8b025a3c507b17.html
看看这篇吧,你们的理解已经是老黄历了~~
事实上,双检锁已经安全了~~
在2001年,双检锁就已经安全了的结论不是那么容易下的吧。
请参考这篇发布于2004年的文章,里面提及了双检查锁存在的问题及JMM的修复。
/developerworks/cn/java/j-jtp02244/
貌似我那篇文章是2006年的~~ 2004年的文章就更老了。。。我想应该不会有多少人还在使用非常古老的jvm吧。。。毕竟JDK5.0与先前的区别是非常大的。至少我看到的关于懒汉式单例的书里只提到过去的java使用懒汉式是不安全的,没有提到现在不能这么使用~~可能也是我的不严谨,不过我想这个问题的应用空间应该也不是很大吧,因为现在很少有需要使用单例的情况了,一般都是交给容器管理。呵呵
babby52561 写道http://dev.csdn.net/author/axman/4c46d233bd8b025a3c507b17.html
看看这篇吧,你们的理解已经是老黄历了~~
事实上,双检锁已经安全了~~
你转贴的那篇文章里,我注意到到以下一段内容,你的结论是否不太全面。。。
那么到底DCL是否真的就没有问题了呢?
否,现在的问题还是可见性问题,但问题转到了同一对象不同字段上面,这个问题已经在以前说过了:
public MyObject{
&&& private static MyO
&&& private Date d = new Data();
&&& public Data getD(){return this.d;}
&&& public static MyObect& getInstance(){
&&&&&&& if(obj == null){
&&&&&&&&&&& synchronized(MyObect .class){
&&&&&&&&&&&&&&& if(obj == null)
&&&&&&&&&&&&&&&&&&& obj = new MyObject();//这里
&&&&&&&&&&& }
&&&&&&& }
&&&&&&&
&&& }
}
一个线程A运行到"这里"时,对于A的工作区中,肯定已经产生一个MyObect对象,而且这时这个对象已经
完成了Data d.现在线程A调用时间到,执行权被切换到另一个线程B来执行,会有什么问题呢?
如果obj不为null,线程B获得了一个obj,但可能obj.getD()却还没有初始化.
这段我也看到了,他说的和大家关注的应该不是一个问题,大家关注的是构造函数未完成前,也就是对象未被完整生成前是否会被另外的线程看到。文章中很明确的提示是在现在的JMM中,应该不存在这种情况,因为未同步的代码是不会被别的线程看到的,只有执行过构造函数的对象才会被复制到主存区。而这一段的问题是存在另一个私有对象d,因为它并不是在构造函数里初始化的,所以不能保证在MyObject的构造函数完成后(对象生成时),d被初始化了。这时在工作区里会有两个对象,d和MyObject,MyObject持有一个d的引用,当MyObject被复制到主存区的时候,d如果还没有被复制过去,就会发生d未被初始化的问题,所以我觉得这个问题应该是说,必须保证构造函数被执行后,这个对象就是可用的,事实上这也是构造函数的意义所在吧。所以我觉得这与单例的懒汉模式是否安全是没有什么关系的,而是和一个对象是否会有不安全对象被逸出有关。不知我这样理解是不是有问题~~
http://dev.csdn.net/author/axman/4c46d233bd8b025a3c507b17.html
看看这篇吧,你们的理解已经是老黄历了~~
事实上,双检锁已经安全了~~
如果真像这篇文章:所说那样的话,1.2或以后的版本就不会有问题了,但这个规则是JMM的规范吗?谁能够确认一下。
引用
确实,在JAVA2(以jdk1.2开始)以前对于实例字段是直接在主储区读写的.所以当一个线程对resource进行分配空间,
初始化和调用构造方法时,可能在其它线程中分配空间动作可见了,而初始化和调用构造方法还没有完成.
但是从JAVA2以后,JMM发生了根本的改变,分配空间,初始化,调用构造方法只会在线程的工作存储区完成,在没有
向主存储区复制赋值时,其它线程绝对不可能见到这个过程.而这个字段复制到主存区的过程,更不会有分配空间后
没有初始化或没有调用构造方法的可能.在JAVA中,一切都是按引用的值复制的.向主存储区同步其实就是把线程工作
存储区的这个已经构造好的对象有压缩堆地址值COPY给主存储区的那个变量.这个过程对于其它线程,要么是resource
为null,要么是完整的对象.绝对不会把一个已经分配空间却没有构造好的对象让其它线程可见.
另外,文章中的第一个双重检测是可以的,这我 也成认是没有问题,因为JDNI实例早已存在,这里的双重正像文中所说那样只是为了减少查找的次数,这与我们讨论的JMM没有关系,这只能说在不同的应用场景中是不一样的。
http://dev.csdn.net/author/axman/4c46d233bd8b025a3c507b17.html
看看这篇吧,你们的理解已经是老黄历了~~
事实上,双检锁已经安全了~~
在2001年,双检锁就已经安全了的结论不是那么容易下的吧。
请参考这篇发布于2004年的文章,里面提及了双检查锁存在的问题及JMM的修复。
/developerworks/cn/java/j-jtp02244/
http://dev.csdn.net/author/axman/4c46d233bd8b025a3c507b17.html
看看这篇吧,你们的理解已经是老黄历了~~
事实上,双检锁已经安全了~~
你转贴的那篇文章里,我注意到到以下一段内容,你的结论是否不太全面。。。
那么到底DCL是否真的就没有问题了呢?
否,现在的问题还是可见性问题,但问题转到了同一对象不同字段上面,这个问题已经在以前说过了:
public MyObject{
&&& private static MyO
&&& private Date d = new Data();
&&& public Data getD(){return this.d;}
&&& public static MyObect& getInstance(){
&&&&&&& if(obj == null){
&&&&&&&&&&& synchronized(MyObect .class){
&&&&&&&&&&&&&&& if(obj == null)
&&&&&&&&&&&&&&&&&&& obj = new MyObject();//这里
&&&&&&&&&&& }
&&&&&&& }
&&&&&&&
&&& }
}
一个线程A运行到"这里"时,对于A的工作区中,肯定已经产生一个MyObect对象,而且这时这个对象已经
完成了Data d.现在线程A调用时间到,执行权被切换到另一个线程B来执行,会有什么问题呢?
如果obj不为null,线程B获得了一个obj,但可能obj.getD()却还没有初始化.
也就是说,加上return,也不能保证同步块的原子性,对吗?
是的,这与加不加上retrun是没有太大的关系的
junJZ_2008 写道
最主要的一点就是,线程可能从任何点切换,这个点可能是某两个语句中,也有可能是从语句中中断,这也是完全有可能的。
如果这样,那第二种的时候,我也在new的时候切换,那不是也不能保证线程安全了吗?
ps:我很少做多线程的东西,不是很了解线程安全
第二种不会的,因为共享的代码块都是放在同步块里的,即在该同步块执行完成后,才能让其他也基于该同步块锁的线程获取锁。双重检测不成立最主要的原因就是 检测 条件不有同步,所以其他线程在执行第一层检测条件时就可能从正在创建对象的线程中抢占CPU,所以就造成了失效
& 上一页 1
junJZ_2008
浏览: 1039443 次
来自: 湖南澧縣
引用String a= &abc&,首先在 ...
谢谢分享matcher.appendReplacement(s ...
完全理解,比网上其他资料都要详细}

我要回帖

更多关于 java单例模式代码 的文章

更多推荐

版权声明:文章内容来源于网络,版权归原作者所有,如有侵权请点击这里与我们联系,我们将及时删除。

点击添加站长微信