1. 程式人生 > >面試官看完我手寫的單例直接驚呆了!

面試官看完我手寫的單例直接驚呆了!

## 前言 單例模式應該算是 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