|
|
@ -99,6 +99,32 @@ public class Singleton { |
|
|
|
|
|
|
|
|
|
|
|
但是由于 CPU 的优化操作,可能会对这几个操作进行乱序执行,第二条和第三条的操作的执行顺序无法保证。如果线程 A 执行到 getInstance() 方法,进入锁块,先执行 第三条操作,然后另外一个线程 B 也执行到 getInstance() 方法,发现 mInstance 不为空了,就直接取走了 mInstance 对象,在使用时就会出错,这就是 DCL 失效问题。而 volatile 能禁止指令重排序。 |
|
|
|
但是由于 CPU 的优化操作,可能会对这几个操作进行乱序执行,第二条和第三条的操作的执行顺序无法保证。如果线程 A 执行到 getInstance() 方法,进入锁块,先执行 第三条操作,然后另外一个线程 B 也执行到 getInstance() 方法,发现 mInstance 不为空了,就直接取走了 mInstance 对象,在使用时就会出错,这就是 DCL 失效问题。而 volatile 能禁止指令重排序。 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
当然,在高版本不加 volatile 其实也没啥,因为 JVM 已经把 new 作为一个原子操作了。 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
DCL 还有一种优化的写法是: |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
```java |
|
|
|
|
|
|
|
class Helper { |
|
|
|
|
|
|
|
private static volatile Helper helper; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
public static Helper getHelper() { |
|
|
|
|
|
|
|
Helper localRef = helper; |
|
|
|
|
|
|
|
if (localRef == null) { |
|
|
|
|
|
|
|
synchronized (Helper.class) { |
|
|
|
|
|
|
|
localRef = helper; |
|
|
|
|
|
|
|
if (localRef == null) { |
|
|
|
|
|
|
|
helper = localRef = new Helper(); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
return localRef; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
// other functions and members... |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
``` |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
##### 静态内部类 |
|
|
|
##### 静态内部类 |
|
|
|
|
|
|
|
|
|
|
|
```java |
|
|
|
```java |
|
|
|