菜菜问一个单例模式加锁的问题

2016-09-23 17:44:52 +08:00
 lawlietxxl

来源: http://www.cnblogs.com/coffee/archive/2011/12/05/inside-java-singleton.html

其中有一个方法

public static SingletonThree getInstance() {
        if (instance == null) { 
            synchronized (SingletonThree.class) {           // 1
                SingletonThree temp = instance;             // 2
                if (temp == null) {
                    synchronized (SingletonThree.class) {   // 3  这里问什么再加一个锁呢?
                        temp = new SingletonThree();        // 4
                    }
                    instance = temp;                        // 5
                }
            }
        }
        return instance;
    }

请问在 //3 的位置,为什么再加一个锁呢?百思不得其解,求教

4194 次点击
所在节点    Java
29 条回复
pubby
2016-09-24 02:04:27 +08:00
@hactrox
@suikator

好奇,文中说第二个同步块的问题是 可能 //5 会被优化到 // 4 的同步块内

但是改成这样呢

public static SingletonThree getInstance() {
if (instance == null) {
synchronized (SingletonThree.class) { // 1
SingletonThree temp = instance; // 2
if (temp == null) {
synchronized (SingletonThree.class) { // 3
temp = new SingletonThree(); // 4
}
synchronized ( OMGOther.class ) {
instance = temp; // 5
}
}
}
}
return instance;
}

不会两个同步块合并优化吧。

不懂 java , phper 路过 -_-
georgema1982
2016-09-24 02:31:45 +08:00
为什么现在还在传播这种过时的设计模式?一个 java 类不应该知道自己的生命周期。
caixiexin
2016-09-24 08:21:17 +08:00
@georgema1982 这个说法有相关文档参考吗?学习下 。
lawlietxxl
2016-09-24 08:31:57 +08:00
@georgema1982 我的锅 😂
GhostFlying
2016-09-24 09:04:07 +08:00
static inner class , jvm 标准保证单例,又不像 enum 有所限制,为什么不用呢
wander2008
2016-09-24 11:17:06 +08:00
static 就够了,不用 violat 了吧
lawlietxxl
2016-09-24 18:00:06 +08:00
大概是因为了解历史能够帮助明白现实的成因。。。
kaedea
2016-09-24 22:02:17 +08:00
1. 锁只需要一个,不过锁前锁后都需要判空;
2. 最简单的方式是“懒汉模式”,则在声明静态成员变量的时候就初始化,这样在加载类的时候就会完成初始化,因此不需要加锁;
georgema1982
2016-09-27 04:28:04 +08:00
@caixiexin 准确地说这是一种现代 java 模式设计 practice 。如果你有兴趣,有可以搜索到很多表达支持这种 practice 的文章。我来说说为什么我认为对自己生命周期无知的 pojo 是一种更好的设计模式的原因。

首先来了解一下 java 设计模式的演变。最初 java 程序员确实是使用对自己生命周期无知的 pojo 类的,也可以说这是一种无设计模式的设计模式。一个类调用另一个类的方法往往是 new 一个 instance ,然后调用新 instance 的方法。但是很快有人注意到这种方式在当时硬件条件下的缺陷,即在多线程模式下,多个做同样事情的 instance 会占用更多的内存,于是在那个时期诞生了很多著名(或者说臭名昭注)的设计模式,最出名的莫过于这种用 private constructor 管理自己生命周期以达到 singleton 的设计模式。

但是现在 java 界又返璞归珍到原先的 pojo 了。为什么?我认为有这些原因

1. private constructor 其实产生了代码冗余。它们想实现一种模式,但是为了实现它,每个这种模式的类都在一遍又一遍地重复代码

2. 由于 constructor 是 private 的,在做单元测试时无法 mock 依赖类。显然在该设计模式产生的年代,单元测试并不被重视。但是现在不同了,单元测试是决定设计模式是否合理的最重要标准

3. 随着注入依赖这一设计模式的产生, pojo 之间的依赖关系变得更加容易管理,从而使得管理自己生命周期的做法变得毫无意义

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

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

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

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

© 2021 V2EX