单例模式 双检测问题请教
source link: https://www.v2ex.com/t/846190
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
public class Singleton {
private volatile static Singleton uniqueInstance;
private Singleton(){};
public static Singleton getInstance(){
if(uniqueInstance == null){
synchronized(Singleton.class){
if(uniqueInstance == null){
uniqueInstance = new Singleton();
}
}
}
return uniqueInstance;
}
}
uniqueInstance = new Singleton() 这行代码虽然会发生指令重排序, 但 synchronized 代码块已经加锁了,每次只有一个线程进入代码块,为啥还要加 volatile ?
hay313955795 3 小时 0 分钟前
链接: https://pan.baidu.com/s/1bb-6itr18pnILc6yZCdvyQ 提取码: fbpy 复制这段内容后打开百度网盘手机 App ,操作更方便哦
jwh199588 2 小时 57 分钟前
xuyang2 2 小时 55 分钟前
Suddoo 2 小时 54 分钟前 via iPhone
wolfie 2 小时 53 分钟前
qgs 2 小时 50 分钟前
Double-checked locking
Inspection info: Reports double-checked locking.
Double-checked locking tries to initialize a field on demand and in a thread-safe manner while avoiding the cost of synchronization. Unfortunately it is not thread-safe when used on a field that is not declared volatile. When using Java 1.4 or earlier, double-checked locking doesn't work even with volatile fields. Read the article linked above for the detailed explanation of the problem.
Example of an incorrect double-checked locking:
class Foo {
private Helper helper = null;
public Helper getHelper() {
if (helper == null)
synchronized(this) {
if (helper == null) helper = new Helper();
}
return helper;
}
}
// other functions and members...
}
MapHacker 2 小时 46 分钟前
pennai 2 小时 45 分钟前
"普通变量与 volatile 变量的区别是,volatile 的特殊规则保证了新值能立即同步到主内存,以及每次使用前立即从主内存刷新。因此我们可以说 volatile 保证了多线程操作时变量的可见性,而普通变量则不能保证这一点。"
出自深入理解 java 虚拟机第三版
mxalbert1996 2 小时 33 分钟前 via Android
liudaolunhuibl 2 小时 33 分钟前
XieQing0428 2 小时 15 分钟前
Leviathann 2 小时 8 分钟前
那不加 volatile 第一个线程接下来进到同步块里的那个判空不是就无效了吗,直接从工作区取的,和外层的判空完全一致了
a794443642 2 小时 0 分钟前 1
1 、为 uniqueInstance 分配一个内存地址 A
2 、在内存地址 A 上初始化 uniqueInstance 实例
3 、把内存 A 的地址赋值给 uniqueInstance 变量
如果不禁止指令重排 可能导致 顺序变为 1 、3 、2
这样的话 当一个线程执行到 1 、3 得到的是一个未初始化的 uniqueInstance 而另一个线程执行到第一个 if 就会返回一个未初始化的 uniqueInstance
golangLover 1 小时 49 分钟前 via Android
fkdog 1 小时 39 分钟前
0:00 ,A 刚进入方法内,uniqueInstance 此时应该是从内存里 copy 了到线程的工作内存里。
0:01 ,B 刚离开同步块,B 完成 uniqueInstance 的初始化,将本地工作线程里的 uniqueInstance 同步回主内存。
由于 uniqueInstance 非 volatile ,A 线程无法感知 B 线程种的同步变化,因此 A 会继续走剩余的逻辑进入同步块。由于同步块里会将 uniqueInstance 变量进行同步,同步完会发现 uniqueInstance 非空,因此需要重新判断一次非空来保证 uniqueInstance 不会被重复初始化。
如果 uniqueInstance 是 volatile ,那么 A 可以感知到 uniqueInstance 的变化,从而避免进入同步块降低吞吐。
总结:
1. 代码进入同步块以后,uniqueInstance 可能已经发生变化,多加一层 null 判断是为了防止重复初始化。
2. 加 volatile 是为了防止代码进入不必要的同步块,提高性能。
TWorldIsNButThis 1 小时 13 分钟前
有很多 design pattern 是为了给 java 、C++这帮 oop 的语言当年没有函数这个抽象擦屁股
搜 design pattern functional programming
当然 fp 语言有自己的 pattern ,比如 monad
另外随着 java pattern matching 能力的到来,Visitor Pattern Considered Pointless (这个是 oracle java 团队成员的一篇博文)
Suddoo 23 分钟前 via iPhone
Suddoo 20 分钟前 via iPhone
Recommend
About Joyk
Aggregate valuable and interesting links.
Joyk means Joy of geeK