多线程安全的单例代码中,为何要两次判断是否为null

denverbenjamin2000 2008-07-14 04:49:35
加精

developerWorks 中国 > Java technology >
Java单例对象同步问题探讨
http://www.ibm.com/developerworks/cn/java/l-singleton/

private static synchronized void syncInit() {
if (instance == null) {
instance = new GlobalConfig();
}
}
public static GlobalConfig getInstance() {
if (instance==null) {
syncInit();
}
return instance;
}
...全文
3430 86 打赏 收藏 转发到动态 举报
写回复
用AI写文章
86 条回复
切换为时间正序
请发表友善的回复…
发表回复
better_huirong 2012-09-13
  • 打赏
  • 举报
回复
学习了。
better_huirong 2012-09-13
  • 打赏
  • 举报
回复
学习了。
pywepe 2011-08-16
  • 打赏
  • 举报
回复
[Quote=引用 73 楼 bloodrate 的回复:]

引用 66 楼 BurningM 的回复:
引用 65 楼 bloodrate 的回复:
这么乍一看上去private static GlobalConfig inst = new GlobalConfig (); 感觉只有优点没有缺点啊,那为什么还会出现懒汉式???

如果你的应用程序里有大量的这种类,而且这些类在初始化时都要做事,那么你的应用程序启动时就要消耗大量的时间和资源了

……
[/Quote]

可能你没做过过或接触过大型应用
cao1991611 2011-07-28
  • 打赏
  • 举报
回复
回帖是一种美德!传说每天回帖即可获得 10 分可用分回帖是一种美德!传说每天回帖即可获得 10 分可用分回帖是一种美德!传说每天回帖即可获得 10 分可用分
lizhi11000 2011-05-01
  • 打赏
  • 举报
回复
学习学习。
yukiMark 2011-04-14
  • 打赏
  • 举报
回复
知识是一点一点积累的哇
xiaotugege 2010-11-22
  • 打赏
  • 举报
回复
[Quote=引用 33 楼 wargrey 的回复:]
《Java与模式》的作者在单例模式一章特别说明了这个问题,他指出类似lz的“双重检查”在java中是存在的,并且建议读者不要做任何有关这方面的尝试。
[/Quote]
这书上对双检锁定描述就是个错误。而他给出的例子在jdk1.2之后就是正确的。
双检锁的隐患在于初始化其他对象上面。而不是单例本身。
zougm 2010-11-16
  • 打赏
  • 举报
回复
[Quote=引用 2 楼 java2000_net 的回复:]

防止2个线程同时发现instance==null,然后同时调用了syncInit()的同步方法。

这样做,第二个进入syncInit的线程将发现那个对象已经不再是null了
避免被二次初始化。


这是单例模式的多线程必须注意的问题!
[/Quote]
正解
刘彬彬 2008-07-27
  • 打赏
  • 举报
回复
楼主学习热情真高,嘿嘿
bloodrate 2008-07-24
  • 打赏
  • 举报
回复
[Quote=引用 74 楼 BurningM 的回复:]
如果你的应用程序要花2分钟的时间启动的话,你觉得用户会不在意么?
[/Quote]

你确定所有的类都会在启动的时候加载吗?我知道servlet都会这样,xxxManager这样的单例类呢,或者是services,是启动时候加载还是第一次使用时候加载??
tonggulu 2008-07-22
  • 打赏
  • 举报
回复
***************************************************************************

思想决定行动,行动决定习惯,习惯决定命运.
程序员在深圳QQ群,交流思想,如饮美酒.

部份专业群介绍:
c++群: 15195967(此群流动性相当大,有时候一个月上百人被迫离群)
java群: 11878667(此群人数较少,但不知道群主会不会让你进群,进群要求很高)
英语学习群: 23864353(此群人气一般,交流也车不够活跃)
c++Ⅱ: 17409451(此群是C++第一群的补充,人气自然差点)
嵌入式开发群: 37489763(此群高手还是有的,气氛一般)
移动开发群: 31501597(此群人气和氛围都还可以)
创业群: 33653422(此群名字就注定了讨论的东西一般没有结果.)


部份高级程序员群(高级群致力于发现和培养专家,人气最旺,淘汰率高,不自信者不要加入):

高级群I:17538442
高级群II:7120862

部份初、中级程序员群:
第三群:2650485
第五群:29537639
第四群:28702746
第六群:10590618
第七群:10543585
第八群:12006492
第九群:19063074
第十群:2883885
第十一群:25460595
第十二群:9663807

深圳程序员QQ群联盟成立2005年,拥有三十个以上的QQ群,人数超三千多人,大量高手,从业于大公司(微软、IBM,SUN,华为)、系统分析员(包括参加过上亿元的项目的架构师)。每个人都自信而上进.推荐:深程高级群I:17538442 深程高级群II:7120862 (深程高级群不欢迎新手,如果在深圳,月薪6K以下的别加入) c++:15195967 java群: 11878667 mobile:31501597嵌入式:37489763
——————————————————————————————————————————
如果你不是第一次看到此广告,说明我们最近T了一些人,因为我们要不断提升群的质量,保证名副其实.
-------------------------------------------------------------------------------------
在通过电邮、新闻组或者聊天室提出技术问题前,检查你有没有做到:
1. 通读手册,试着自己找答案。
2. 在FAQ里找答案(一份维护得好的FAQ可以包罗万象:)。
3. 在网上搜索(个人推荐google~)。
4. 向你身边精于此道的朋友打听。
我想我们首先应该靠自己解决问题,然后才是问
------------------------------------------------------------------------------------------------------

技术QQ群是一个体现群体智慧的地方,无价值的发言会给别人带来噪音和负担,如果不同意以上观点的请勿加入!

*****************************************************************************
BurningM 2008-07-22
  • 打赏
  • 举报
回复
如果你的应用程序要花2分钟的时间启动的话,你觉得用户会不在意么?
zou_wei_forever 2008-07-22
  • 打赏
  • 举报
回复
[Quote=引用 15 楼 jdlsfl 的回复:]
学习
[/Quote]
bloodrate 2008-07-22
  • 打赏
  • 举报
回复
[Quote=引用 66 楼 BurningM 的回复:]
引用 65 楼 bloodrate 的回复:
这么乍一看上去private static GlobalConfig inst = new GlobalConfig (); 感觉只有优点没有缺点啊,那为什么还会出现懒汉式???

如果你的应用程序里有大量的这种类,而且这些类在初始化时都要做事,那么你的应用程序启动时就要消耗大量的时间和资源了
[/Quote]

启动时消耗很大资源?这个很关键么?大家不再以启动慢点吧?
我叫尐桀 2008-07-21
  • 打赏
  • 举报
回复
都是高人~~学习了
yrnaaa 2008-07-20
  • 打赏
  • 举报
回复
学习。。。
JogenChen 2008-07-20
  • 打赏
  • 举报
回复
值的学习
JogenChen 2008-07-20
  • 打赏
  • 举报
回复
值的学习
JogenChen 2008-07-20
  • 打赏
  • 举报
回复
值的学习
denverbenjamin2000 2008-07-19
  • 打赏
  • 举报
回复
转自
Concurrent and Real-Time Programming in Java
by Andy Wellings John Wiley & Sons © 2004

However, synchronization can be expensive, and there are times when a programmer might want to use shared variables without an associated monitor lock. One example is the so-called double-checked locking idiom [Schmidt and Harrison, 1997]. In this idiom, a singleton resource is to be created; this resource may or may not be used during a particular execution of the program. Furthermore, creating the resource is an expensive operation and should be deferred until it is required. A simple and intuitive implementation of this requirement is the following:

public class ResourceController {

public static synchronized Resource getResource() {
if (resource == null) resource = new Resource();
return resource;
}

private static Resource resource = null;
}

The problem with this solution is that a lock is required on every access to the resource. In fact, it is only necessary to synchronize on creation of the resource, as the resource will provide its own synchronization when the threads use it. The double-checked locking idiom attempts to solve this with the following algorithm.

public class ResourceController {

public static Resource getResource() {
if(resource == null) {
synchronized (ResourceController.class) {
if(resource == null) resource = new Resource();
}
}
return resource;
}

private static Resource resource = null;
}

Here, once the resource has been allocated, in theory, there is no need to execute the synchronized statement. In order to understand whether this program functions as intended, it is necessary to have a deeper understanding of both the relationship between Java threads and memory and the potential optimizations that a compiler or processor may perform.

The relationship between threads and memory is defined in the Java Language Specification Chapter 17 [Gosling, Joy and Steele, 1996] and is known as the Java Memory Model (JMM). Unfortunately, this model has come under much criticism over recent years because it is hard to understand [Pugh, 1999]; as a result it has been revamped in Java 1.5. In the JMM, each thread is considered to have access to its own working memory as well as the main memory that is shared between all threads. This working memory is used to hold copies of the data that resides in the shared main memory. It is an abstraction of data held in registers or data held in local caches on a multiprocessor system. The JVM transfers data between the main shared memory and a thread's local memory as and when required. It is a requirement that

a thread's working memory is invalidated when the thread acquires an object's lock; that is, inside a synchronized method or statement any initial read of a shared variable must read the value from main memory,

a thread's working memory is written back to the main memory when the thread releases a lock; that is, before a synchronized method or statement finishes, any variables written to during the method or statement must be written back to main memory.

Data may be written to the main memory at other times as well, however, the programmer just cannot tell when.

In order to give flexibility to compiler writers and JVM implementors, the JMM allows code to be optimized and reordered as long as it maintains "as-if-serial" semantics. That is, the result of executing the code is the same as the result that would be obtained if the code was executed sequentially. For sequential Java programs, the programmer will not be able to detect these optimizations and reordering. However, in concurrent systems, they will manifest themselves unless the program is properly synchronized.

Consider again the double-checked locking algorithm. Now suppose that a compiler implements the resource = new Resource () statement logically as follows:

tmp = create memory for the Resource class
// tmp points to memory
Resource.construct(tmp)
// runs the constructor to initialize
resource = tmp // set up resource

Now as a result of optimizations or reordering, suppose the statements are executed in the following order

tmp = create memory for the Resource class
// tmp points to memory
resource = tmp
Resource.construct(tmp)
// run the constructor to initialize

It is easy to see that there is a period of time when the resource reference has a value, but the Resource object has not been initialized. It is now possible to construct an interleaving of the double-checked locking algorithm, when one thread is in the process of creating the resource, a second thread sees a partially created object (outside of the synchronized block) and tries to use it. It is not possible to predict what will happen as it depends on the resource itself [Pugh 2000].

Even more insidious problems may occur if the resource is fully initialized by thread, T1, but the initialization touches other objects. Now these objects may have been written back to memory when T1 exits the synchronized statement, but another thread, T2, will see an initialized resource that potentially references objects that it already has in its local memory. Unfortunately, as it has not performed a lock operation, there is no requirement for the JVM to reload those objects, and so T2 sees stale data.

Important note The double-checked locking algorithm illustrates that synchronized methods (and statements) in Java serve a dual purpose. Not only do they enable mutual exclusive access to a shared resource but they also ensure that data written by one thread (the writer) becomes visible to another thread (the reader). The visibility of data written by the writer is only guaranteed when it releases a lock that is subsequently acquired by the reader.


Volatile fields

Java allows fields to be defined as volatile. The Java Language Specification requires that a volatile field not be held in local memory and that all reads and writes go straight to main memory. Furthermore, operations on volatile fields must be performed in exactly the order that a thread requests. A further rule requires that volatile double or long variables must be read and written atomically.

Warning Objects and arrays are accessed via references and, therefore, marking them as volatile only applies to the references, not to the fields of the objects or the components of the arrays. It is not possible to specify that elements of an array are volatile.

加载更多回复(65)

62,614

社区成员

发帖
与我相关
我的任务
社区描述
Java 2 Standard Edition
社区管理员
  • Java SE
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧