File tree 1 file changed +40
-0
lines changed
1 file changed +40
-0
lines changed Original file line number Diff line number Diff line change @@ -80,3 +80,43 @@ func main() {
80
80
}
81
81
```
82
82
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
+
You can’t perform that action at this time.
0 commit comments