精华帖 (0) :: 良好帖 (1) :: 新手帖 (0) :: 隐藏帖 (0)
|
|
---|---|
作者 | 正文 |
发表时间:2010-09-03
引用 另外请教大家个问题
在构造方法中使用 xxx=this,尽管没有错误,但是NetBeans会提示"构造函数中泄漏 this"...在一般方法中使用没有提示...这是什么意思?会有什么问题? 可以看看java并发编程这书,讲得非常不错,我引用它的一段原话 引用 对象只有通过构造函数返回后,才处于可预言、稳定的状态,所以从构造函数内部发布的对象,只是一个未完成构造的对象。甚至即使是在构造函数的最后一行发布的引用也是如此。如果this引用在构造过程中逸出,这个的对象被认为是“没有正确构建的” 引用 不要让this引用在构造期间逸出
|
|
返回顶楼 | |
发表时间:2010-09-03
icanfly 写道 引用 另外请教大家个问题
在构造方法中使用 xxx=this,尽管没有错误,但是NetBeans会提示"构造函数中泄漏 this"...在一般方法中使用没有提示...这是什么意思?会有什么问题? 可以看看java并发编程这书,讲得非常不错,我引用它的一段原话 引用 对象只有通过构造函数返回后,才处于可预言、稳定的状态,所以从构造函数内部发布的对象,只是一个未完成构造的对象。甚至即使是在构造函数的最后一行发布的引用也是如此。如果this引用在构造过程中逸出,这个的对象被认为是“没有正确构建的” 引用 不要让this引用在构造期间逸出
谢谢谢谢 这也刚好对实例完整性的的意思进行了阐述 但jeff.key提到的完整性问题,我觉得急切加载这个问题上应该不会碰上:JVM在加载这个类的时候就实例化了这个对象,不会因为多线程的问题导致这个对象不完整(多线程尚未启动) |
|
返回顶楼 | |
发表时间:2010-09-03
panhf2003 写道 qjtttt 写道 jeff.key 写道 引用 2.急切(eagerly)实例化,也就是声明实例的引用变量时直接生成一个实例。
private static Singleton st=new Singleton(); 优点:万金油,没有突出的缺点。 缺点:被类加载器加载时就可能(与JVM的实现也有关系)生成实例,而非用到时生成。--并非不可接受。 这个最好能声明成final,因为按照新的(java 5以后)的JMM(Java Memory Model)中对于final的语义定义,可以确保你收到的实例是完整的。没有定义成final似乎不能有这个保证。 你确认么?static + final 修饰?常量?不能被修改属性的实例...那这个单例还有什么价值没有? 这位兄弟对final的作用有点误解,static + final 修饰只是说该引用不能指向别的对象了,并非说不能修改该实例的属性。 哦哦,平时不太会定义这样的常量,大多都是基本类型,而且一般都不去修改,搞混了,呵呵 |
|
返回顶楼 | |
发表时间:2010-09-04
runshine 写道 请问"实例是完整的"这句话是什么意思呢?
其实双重检查是可行的,不过要保证实例的完整构造后才能使用 //3.双重检测加锁。 private static BgImage instance= null; if(instance==null) { synchronized(Singleton.class) { if(instance==null) { BgImage tmp = new Singleton(); //singleton = new Singleton ();new 只是把地址给了singleton,但是此时还没有执行构造器,也就是说singleton只分配了内存,但是内部的成员变量等还没有初始化,即singleton此时代表一个不完整的实例,其他线程可能拿到此实例(因为此时singleton!=null,但singleton不完整) instance = tmp;//此时tmp已经完整了 } } } runshine 写道 jeff.key 写道 引用 2.急切(eagerly)实例化,也就是声明实例的引用变量时直接生成一个实例。
private static Singleton st=new Singleton(); 优点:万金油,没有突出的缺点。 缺点:被类加载器加载时就可能(与JVM的实现也有关系)生成实例,而非用到时生成。--并非不可接受。 这个最好能声明成final,因为按照新的(java 5以后)的JMM(Java Memory Model)中对于final的语义定义,可以确保你收到的实例是完整的。没有定义成final似乎不能有这个保证。 请问"实例是完整的"这句话是什么意思呢? 加了final固然最好 但在HeadFirst中并没有提到要加(实际上它确实也没加) 有没有证据证明不加会出现问题?这种说法的出处? --谢谢icanfly在第二页给出的说法,刚好也解释了这里说的完整性的问题...不过我觉得急切加载应该不会碰上,JVM在加载这个类的时候就实例化了这个对象,不会因为多线程的问题导致这个对象不完整(多线程尚未启动) 楼上的qjtttt兄显然还没明白static+final的含义... 另外,关于双检测中volatile的必要性产生了疑问 在core java(第八版)的14.5.8章节以及think in java(第四版)的21.3.3章节 都有这么一种描述: 同步机制强制在处理器系统中,一个任务作出的修改必须在另一个任务中是可视的...如果一个域完全由synchronized方法或语句块来防护,那就不必将其设置为是volatile的.(出自think in java) 如果你用锁来保护可以被多个线程访问的代码,那么可以不用考虑这种问题(出自core java,"问题"是指可视性) 如果按照这两本书的说法,双检测中已经使用了同步锁防护,那么那个属性就没必要使用volatile了.请大家指正下. 另外,"构造函数中泄漏 this"到底是什么意思啊... - -! |
|
返回顶楼 | |
发表时间:2010-09-04
最后修改:2010-09-04
runshine 写道 请问"实例是完整的"这句话是什么意思呢?
其实双重检查是可行的,不过要保证实例的完整构造后才能使用 //3.双重检测加锁。 private static BgImage instance= null; if(instance==null) { synchronized(Singleton.class) { if(instance==null) { BgImage tmp = new Singleton(); //singleton = new Singleton ();new 只是把地址给了singleton,但是此时还没有执行构造器,也就是说singleton只分配了内存,但是内部的成员变量等还没有初始化,即singleton此时代表一个不完整的实例,其他线程可能拿到此实例(因为此时singleton!=null,但singleton不完整) instance = tmp;//此时tmp已经完整了 } } } 看着楼上发的代码,真痛心,代码写的好乱(拼写错误好多啊),尽管表达了自己的意思.但是你这样写,与直接new出一个对象赋值给实例的私有静态属性有何不同? |
|
返回顶楼 | |
发表时间:2010-09-05
static + final 修饰只是说该引用不能指向别的对象了,并非说不能修改该实例的属性。
应该是这样的 !!lz误解了吧、 另外你说的那个遗漏问题!做等高手吧!@! |
|
返回顶楼 | |
发表时间:2010-09-05
其实哪些所谓双重检查更能导致的问题,jdk应该解决了吧
这么多年了,我反正平时都是用得双重检查也没有发现问题 |
|
返回顶楼 | |
发表时间:2010-09-05
^ ^ 我的代码只是复制了lz的,然后修改了下
但是你这样写,与直接new出一个对象赋值给实例的私有静态属性有何不同? 看书时看到过,要分析ClassName instance = new ClassName();后产生的汇编代码,才知道为什么会这样 罪魁祸首就是运行时优化,导致指令执行顺序发生调换A test case showing that it doesn't work一节有汇编码 首先明确需要单例构造的实例,都是重对象——比如HibernateSessionFactory,他们需要的时间比较长,可能需要500ms 大意是:new操作后堆分配了内存这样instance就非空了,但是此时对象构造器还没执行——我们称之为不完整对象(他的构造器还没有运行呢,大量的成员变量还没有构造完,需要大约500ms才可完全初始化完毕); 但是:既然instance非空,那么其他线程执行getInstance()时因为检测到instance非空,就得到了此对象,从而执行instance.aMethod();鬼知道会发生什么事情 看着楼上发的代码,真痛心,代码写的好乱(拼写错误好多啊),尽管表达了自己的意思.但是你这样写,与直接new出一个对象赋值给实例的私有静态属性有何不同? fengjia10 写道 skzr.org 写道 runshine 写道 请问"实例是完整的"这句话是什么意思呢?
其实双重检查是可行的,不过要保证实例的完整构造后才能使用 //3.双重检测加锁。 private static BgImage instance= null; if(instance==null) { synchronized(Singleton.class) { if(instance==null) { BgImage tmp = new Singleton(); //singleton = new Singleton ();new 只是把地址给了singleton,但是此时还没有执行构造器,也就是说singleton只分配了内存,但是内部的成员变量等还没有初始化,即singleton此时代表一个不完整的实例,其他线程可能拿到此实例(因为此时singleton!=null,但singleton不完整) instance = tmp;//此时tmp已经完整了 } } } 看着楼上发的代码,真痛心,代码写的好乱(拼写错误好多啊),尽管表达了自己的意思.但是你这样写,与直接new出一个对象赋值给实例的私有静态属性有何不同? |
|
返回顶楼 | |
发表时间:2010-09-05
^ ^ 我的代码只是复制了lz的,然后修改了下
但是你这样写,与直接new出一个对象赋值给实例的私有静态属性有何不同? 看书时看到过,要分析ClassName instance = new ClassName();后产生的汇编代码,才知道为什么会这样 罪魁祸首就是运行时优化,导致指令执行顺序发生调换A test case showing that it doesn't work一节有汇编码 首先明确需要单例构造的实例,都是重对象——比如HibernateSessionFactory,他们需要的时间比较长,可能需要500ms 大意是:new操作后堆分配了内存这样instance就非空了,但是此时对象构造器还没执行——我们称之为不完整对象(他的构造器还没有运行呢,大量的成员变量还没有构造完,需要大约500ms才可完全初始化完毕); 但是:既然instance非空,那么其他线程执行getInstance()时因为检测到instance非空,就得到了此对象,从而执行instance.aMethod();鬼知道会发生什么事情 fengjia10 写道 看着楼上发的代码,真痛心,代码写的好乱(拼写错误好多啊),尽管表达了自己的意思.但是你这样写,与直接new出一个对象赋值给实例的私有静态属性有何不同?
fengjia10 写道 skzr.org 写道 runshine 写道 请问"实例是完整的"这句话是什么意思呢?
其实双重检查是可行的,不过要保证实例的完整构造后才能使用 //3.双重检测加锁。 private static BgImage instance= null; if(instance==null) { synchronized(Singleton.class) { if(instance==null) { BgImage tmp = new Singleton(); //singleton = new Singleton ();new 只是把地址给了singleton,但是此时还没有执行构造器,也就是说singleton只分配了内存,但是内部的成员变量等还没有初始化,即singleton此时代表一个不完整的实例,其他线程可能拿到此实例(因为此时singleton!=null,但singleton不完整) instance = tmp;//此时tmp已经完整了 } } } 看着楼上发的代码,真痛心,代码写的好乱(拼写错误好多啊),尽管表达了自己的意思.但是你这样写,与直接new出一个对象赋值给实例的私有静态属性有何不同? 既然知道优化会重排序,那么你的 引用 instance = tmp;//此时tmp已经完整了 这句话你能保证不会被排序到 BgImage tmp = new Singleton();这个的中间环节或是什么的吗?你这种做法好像国外早就有论证是错误的吧,具体哪篇帖子给忘了。
|
|
返回顶楼 | |
发表时间:2010-09-05
skzr.org 写道 ^ ^ 我的代码只是复制了lz的,然后修改了下
但是你这样写,与直接new出一个对象赋值给实例的私有静态属性有何不同? 看书时看到过,要分析ClassName instance = new ClassName();后产生的汇编代码,才知道为什么会这样 罪魁祸首就是运行时优化,导致指令执行顺序发生调换A test case showing that it doesn't work一节有汇编码 首先明确需要单例构造的实例,都是重对象——比如HibernateSessionFactory,他们需要的时间比较长,可能需要500ms 大意是:new操作后堆分配了内存这样instance就非空了,但是此时对象构造器还没执行——我们称之为不完整对象(他的构造器还没有运行呢,大量的成员变量还没有构造完,需要大约500ms才可完全初始化完毕); 但是:既然instance非空,那么其他线程执行getInstance()时因为检测到instance非空,就得到了此对象,从而执行instance.aMethod();鬼知道会发生什么事情 fengjia10 写道 看着楼上发的代码,真痛心,代码写的好乱(拼写错误好多啊),尽管表达了自己的意思.但是你这样写,与直接new出一个对象赋值给实例的私有静态属性有何不同?
fengjia10 写道 skzr.org 写道 runshine 写道 请问"实例是完整的"这句话是什么意思呢?
其实双重检查是可行的,不过要保证实例的完整构造后才能使用 //3.双重检测加锁。 private static BgImage instance= null; if(instance==null) { synchronized(Singleton.class) { if(instance==null) { BgImage tmp = new Singleton(); //singleton = new Singleton ();new 只是把地址给了singleton,但是此时还没有执行构造器,也就是说singleton只分配了内存,但是内部的成员变量等还没有初始化,即singleton此时代表一个不完整的实例,其他线程可能拿到此实例(因为此时singleton!=null,但singleton不完整) instance = tmp;//此时tmp已经完整了 } } } 看着楼上发的代码,真痛心,代码写的好乱(拼写错误好多啊),尽管表达了自己的意思.但是你这样写,与直接new出一个对象赋值给实例的私有静态属性有何不同? 既然知道优化会重排序,那么你的 引用 instance = tmp;//此时tmp已经完整了 这句话你能保证不会被排序到 BgImage tmp = new Singleton();这个的中间环节或是什么的吗?你这种做法好像国外早就有论证是错误的吧,具体哪篇帖子给忘了。好像就是这个 http://www.cs.umd.edu/~pugh/java/memoryModel/DoubleCheckedLocking.html |
|
返回顶楼 | |