Skip to content

Commit aadd3cc

Browse files
Update 设计模式.md
1 parent 36a3c40 commit aadd3cc

File tree

1 file changed

+40
-0
lines changed

1 file changed

+40
-0
lines changed

设计模式.md

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,3 +80,43 @@ func main() {
8080
}
8181
```
8282

83+
84+
85+
```java
86+
public class DoubleCheckedLock {
87+
88+
// 使用volatile修饰禁止重排序
89+
private volatile static DoubleCheckedLock instance;
90+
91+
private DoubleCheckedLock() {
92+
//构造器必须私有 不然直接new就可以创建
93+
}
94+
95+
96+
public static DoubleCheckedLock getInstance() {
97+
//第一次判断,假设会有好多线程,如果doubleLock没有被实例化,那么就会到下一步获取锁,只有一个能获取到,
98+
//如果已经实例化,那么直接返回了,减少除了初始化时之外的所有锁获取等待过程
99+
if (instance == null) {
100+
//同步
101+
synchronized (DoubleCheckedLock.class) {
102+
//第二次判断是因为假设有两个线程A、B,两个同时通过了第一个if,然后A获取了锁,进入然后判断doubleLock是null,
103+
// 他就实例化了doubleLock,然后他出了锁,这时候线程B经过等待A释放的锁,B获取锁了,
104+
// 如果没有第二个判断,那么他还是会去new DoubleLock(),再创建一个实例,所以为了防止这种情况,需要第二次判断
105+
if (instance == null) {
106+
//下面这句代码其实分为三步:
107+
//1.开辟内存分配给这个对象
108+
//2.初始化对象
109+
//3.将内存地址赋给虚拟机栈内存中的doubleLock变量
110+
//注意上面这三步,第2步和第3步的顺序是随机的,这是计算机指令重排序的问题
111+
//假设有两个线程,其中一个线程执行下面这行代码,如果第三步先执行了,就会把没有初始化的内存赋值给doubleLock
112+
//然后恰好这时候有另一个线程执行了第一个判断if(doubleLock == null),然后就会发现doubleLock指向了一个内存地址
113+
//这另一个线程就直接返回了这个没有初始化的内存,所以要防止第2步和第3步重排序
114+
instance = new DoubleCheckedLock();
115+
}
116+
}
117+
}
118+
return instance;
119+
}
120+
}
121+
```
122+

0 commit comments

Comments
 (0)