面試官看完我手寫的單例直接驚呆了!
阿新 • • 發佈:2020-09-28
## 前言
單例模式應該算是 23 種設計模式中,最常見最容易考察的知識點了。經常會有面試官讓手寫單例模式,別到時候傻乎乎的說我不會。
之前,我有介紹過單例模式的幾種常見寫法。還不知道的,傳送門看這裡:
[設計模式之單例模式](https://mp.weixin.qq.com/s/1AbZGp6uwCNR0R3TYdDRlg)
本篇文章將展開一些不太容易想到的問題。帶著你思考一下,傳統的單例模式有哪些問題,並給出解決方案。讓面試官眼中一亮,心道,小夥子有點東西啊!
以下,以 DCL 單例模式為例。
## DCL 單例模式
DCL 就是 **D**ouble **C**heck **L**ock 的縮寫,即雙重檢查的同步鎖。程式碼如下,
```java
public class Singleton {
//注意,此變數需要用volatile修飾以防止指令重排序
private static volatile Singleton singleton = null;
private Singleton(){
}
public static Singleton getInstance(){
//進入方法內,先判斷例項是否為空,以確定是否需要進入同步程式碼塊
if(singleton == null){
synchronized (Singleton.class){
//進入同步程式碼塊時再次判斷例項是否為空
if(singleton == null){
singleton = new Singleton();
}
}
}
return singleton;
}
}
```
乍看,以上的寫法沒有什麼問題,而且我們確實也經常這樣寫。
但是,問題來了。
### DCL 單例一定能確保執行緒安全嗎?
有的小夥伴就會說,你這不是廢話麼,大家不都這樣寫麼,肯定是執行緒安全的啊。
確實,在正常情況,我可以保證呼叫 `getInstance` 方法兩次,拿到的是同一個物件。
但是,我們知道 Java 中有個很強大的功能——**反射**。對的,沒錯,就是他。
通過反射,我就可以破壞單例模式,從而呼叫它的建構函式,來建立不同的物件。
```java
public class TestDCL {
public static void main(String[] args) throws Exception {
Singleton singleton1 = Singleton.getInstance();
System.out.println(singleton1.hashCode()); // 723074861