来看看这个单例模式呗

2015-05-25 16:22:13 +08:00
 Registering

看到EventBus和Universay image loader的代码中,单例模式都这样写-----两次判断是否为空
平时我的习惯是只判断一次。

看有些博客说,这样可以防止并发问题,而且提高效率,,,不大理解

public static EventBus getDefault() {  
   if (defaultInstance == null) {  
       synchronized (EventBus.class) {  
           if (defaultInstance == null) {  
               defaultInstance = new EventBus();  
           }  
       }  
   }  
   return defaultInstance;  
   }
3903 次点击
所在节点    程序员
20 条回复
bengol
2015-05-25 16:36:38 +08:00
Septembers
2015-05-25 16:39:08 +08:00
如果高度强调并发性能那就需要考虑无锁实现了
jadetang
2015-05-25 16:41:45 +08:00
effective 第三条
用私有构造器或者枚举类型强化单例属性。
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>
crazyxin1988
2015-05-25 16:53:29 +08:00
想理解这个问题,推荐你看 深入理解Java虚拟机 这本书
大部分的博客也是抄来抄去 说不清原理
pandorla1984
2015-05-25 16:59:01 +08:00
简单地说就是你检查null之后lock之前可能那个值已经发生了改变,不是null了 (另一个线程对其进行了修改)。所以lock之后要再检查一次是否是null。
dullwit
2015-05-25 17:04:23 +08:00
Rocko
2015-05-25 17:06:22 +08:00
简单说就是在安全地初始化实例后,以后每次拿实例就不用经过锁了。
zhchaos
2015-05-25 17:20:18 +08:00
用枚举类型去实现单例吧,最简单,还不会有问题
bigredapple
2015-05-25 17:48:01 +08:00
double check
sunjiayao
2015-05-25 17:48:22 +08:00
只判断一次会出现重复赋值的现象
miao1007
2015-05-25 18:08:17 +08:00
双重检验,第一次检验不用担心同步锁降低的效率,第二次检验可以去掉线程同步问题。不要用枚举,现在Android开发都是JDK7了。
anerevol
2015-05-25 18:14:12 +08:00
话说objective-C,在我不知道dispatch_once之前我也一直这么写的。
Registering
2015-05-25 20:06:23 +08:00
@crazyxin1988
有这本书(作者周志明),选择性的看了一部分而已,还没看到这个问题相关的章节,,,
记得在哪一章吗?今晚我翻阅一下
crazyxin1988
2015-05-25 20:34:14 +08:00
@Registering
12章 java内存模型与线程
里面重点讲volatile
双锁检测只是提到
617019296
2015-05-26 09:00:20 +08:00
@pandorla1984 这不敢苟同,,那你直接锁不就行了,,何必先检查再锁。。。
Registering
2015-05-26 10:49:36 +08:00
@617019296

第一次验证是为了避免每次都加锁
第二次验证
当你有10个线程同时执行完第一步验证,其中一个线程拿到锁,如果没有第二步验证,则该线程直接创建对象。然后其他线程依次获得锁(依然没有第二步验证),其他线程都各自创建对象。这就出现了同步问题,违背了单例
Chrisplus
2015-05-26 15:46:08 +08:00
@Registering 说的很清楚,谢谢
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;
}
}
pandorla1984
2015-06-01 09:36:22 +08:00
@617019296 那岂不是每次都要锁。。。效率较低

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/193589

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX