看到EventBus和Universay image loader的代码中,单例模式都这样写-----两次判断是否为空
平时我的习惯是只判断一次。
看有些博客说,这样可以防止并发问题,而且提高效率,,,不大理解
public static EventBus getDefault() {
if (defaultInstance == null) {
synchronized (EventBus.class) {
if (defaultInstance == null) {
defaultInstance = new EventBus();
}
}
}
return defaultInstance;
}
1
bengol 2015-05-25 16:36:38 +08:00 1
|
2
Septembers 2015-05-25 16:39:08 +08:00 via Android
如果高度强调并发性能那就需要考虑无锁实现了
|
3
jadetang 2015-05-25 16:41:45 +08:00
effective 第三条
用私有构造器或者枚举类型强化单例属性。 |
4
shiznet 2015-05-25 16:52:30 +08:00
Java如果是1.4及以前的版本,需要注意下这个:
http://zh.wikipedia.org/wiki/%E5%8F%8C%E9%87%8D%E6%A3%80%E6%9F%A5%E9%94%81%E5%AE%9A%E6%A8%A1%E5%BC%8F <quote> 在J2SE 1.4或更早的版本中使用双重检查锁有潜在的危险,有时会正常工作:区分正确实现和有小问题的实现是很困难的。取决于编译器,线程的调度和其他并发系统活动,不正确的实现双重检查锁导致的异常结果可能会间歇性出现。重现异常是十分困难的。 </quote> |
5
crazyxin1988 2015-05-25 16:53:29 +08:00
想理解这个问题,推荐你看 深入理解Java虚拟机 这本书
大部分的博客也是抄来抄去 说不清原理 |
6
pandorla1984 2015-05-25 16:59:01 +08:00 1
简单地说就是你检查null之后lock之前可能那个值已经发生了改变,不是null了 (另一个线程对其进行了修改)。所以lock之后要再检查一次是否是null。
|
7
dullwit 2015-05-25 17:04:23 +08:00 2
|
8
Rocko 2015-05-25 17:06:22 +08:00 via Android 1
简单说就是在安全地初始化实例后,以后每次拿实例就不用经过锁了。
|
9
zhchaos 2015-05-25 17:20:18 +08:00
用枚举类型去实现单例吧,最简单,还不会有问题
|
10
bigredapple 2015-05-25 17:48:01 +08:00
double check
|
11
sunjiayao 2015-05-25 17:48:22 +08:00
只判断一次会出现重复赋值的现象
|
12
miao1007 2015-05-25 18:08:17 +08:00
双重检验,第一次检验不用担心同步锁降低的效率,第二次检验可以去掉线程同步问题。不要用枚举,现在Android开发都是JDK7了。
|
13
anerevol 2015-05-25 18:14:12 +08:00
话说objective-C,在我不知道dispatch_once之前我也一直这么写的。
|
14
Registering OP |
15
crazyxin1988 2015-05-25 20:34:14 +08:00
|
16
617019296 2015-05-26 09:00:20 +08:00 via Android
@pandorla1984 这不敢苟同,,那你直接锁不就行了,,何必先检查再锁。。。
|
17
Registering OP @617019296
第一次验证是为了避免每次都加锁 第二次验证 当你有10个线程同时执行完第一步验证,其中一个线程拿到锁,如果没有第二步验证,则该线程直接创建对象。然后其他线程依次获得锁(依然没有第二步验证),其他线程都各自创建对象。这就出现了同步问题,违背了单例 |
18
Chrisplus 2015-05-26 15:46:08 +08:00
@Registering 说的很清楚,谢谢
|
19
wallacedong 2015-05-26 15:48:48 +08:00
public class Singleton {
// Private constructor prevents instantiation from other classes private Singleton() { } /** * SingletonHolder is loaded on the first execution of Singleton.getInstance() * or the first access to SingletonHolder.INSTANCE, not before. */ private static class SingletonHolder { public static final Singleton INSTANCE = new Singleton(); } public static Singleton getInstance() { return SingletonHolder.INSTANCE; } } |
20
pandorla1984 2015-06-01 09:36:22 +08:00
@617019296 那岂不是每次都要锁。。。效率较低
|