在面試初級和高級開發時,一般會問設計模式的問題。通常會讓寫下單例模式的實現方法,或者讓結合項目,說下用過的設計模式,在本文里,就將講述單例模式的多種寫法,以此告訴大家如何在面試中展示實力。
如果在項目里,多個運行實例都會從同一個配置文件里讀取發送郵件的列表,那么我們就可以用單例模式來創建這個讀配置文件的類。我們先來看下單線程情況下單例模式的寫法。
1 public class MailListReader { 2 private static MailListReader reader = null; 3 private MailListReader(){}//構造函數私有 4 //向外部開放一個公有的靜態函數來提供對象 5 public static MailListReader getInstance() { 6 if(reader == null) 7 reader = new MailListReader(); 8 return reader; 9 } 10 //提供郵件列表的方法 11 List<String> provideList() 12 { 省略提供郵件列表的代碼 } 13 }
在上述的代碼里,我們可以看到實現單例模式的兩大要素,第一,第3行提供的構造函數是私有的,這樣外部代碼就無法通過調用構造函數來創建MailListReader對象。第二,會通過諸如第5行的代碼向外界提供read實例,而且在這個方法里,只有當read對象為null時,才創建並返回該對象。
如果程序是運行在單線程環境下,那么上述實現方式確實能滿足單例的需求,但在多線程的情況下,出現多個線程同時調用getInstance方法,那么就無法保證單例了。
確實,我們可以通過加synchronized來保證多線程場景里只有一個MailListReader對象被創建,代碼改寫如下。
1 public class MailListReader { 2 private static MailListReader reader = null; 3 private MailListReader(){}//構造函數私有 4 public static MailListReader getInstance() { 5 Synchronized(MailListReader.class){ 6 if(reader == null) 7 reader = new MailListReader(); 8 } 9 return reader; 10 } 11 //省略提供郵件列表的方法 12 }
我們把第7行的new的動作包含在第5行的Synchronized代碼塊里,這樣這個new代碼在同一個時間段里只能被一個線程調用,多個線程同時到來時會出現排隊的情況,這樣效率有些低下。所以,我們還可以通過如下的“雙重檢查”的方式來兼顧線程安全和性能。
1 public class MailListReader { 2 private static MailListReader reader = null; 3 private MailListReader(){}//構造函數私有 4 public static MailListReader getInstance() { 5 if(reader== null){ 6 synchronized (MailListReader.class){ 7 if(reader == null){ 8 reader = new MailListReader (); 9 } 10 } 11 } 12 return reader; 13 } 14 //省略提供郵件列表的方法 15 }
我們在getInstance方法里的第5和第7行兩個地方通過兩個if來檢查,這就是“雙重檢查”。這里我們在加鎖前做了一個是否為空的判斷。通過這個判斷我們能看到了是否有其它線程得到reader對象,這樣就可以避免第6行的鎖對象的操作,從而能避免多線程排隊的情況。
大家完全可以通過你在項目中的實際案例,用單例模式來說明自己對設計模式的理解,而且可以由淺到深地一直講到“雙重檢查”方式,這樣面試官就能知道,你不僅知道這種模式最基本的寫法,還知道掌握如何在多線程中應用的高級技能,更為重要的是,大家能通過實際案例,向面試官說明你不僅知道理論,而會應用。
此外,在講完上述回答后,大家可以再往如下兩個方向擴展,第一可以繼續說,除了單例模式外,在我們項目里,還用到其它設計模式,然后再結合案例說明,或者再圍繞剛才單例模式里提到的線程安全,再擴展出去說,除了在單例模式外,在我們項目里還會考慮其它的線程並發因素,比如對一些多線程間都需要用的鍵值對緩存,我們是放入ConcurrentHashMap,(或者引出Lock,ThreadLocal等線程相關話題),然后再展開,這樣就可以繼續在自己熟悉的范圍內回答問題。
大家可以想象下,如果初級開發一方面照此說辭,很好地證明了設計模式方面的能力,另一方面再通過准備加引導技術,不僅可以展示基礎技能 ,更能有效地展示諸如底層代碼等技能,這對成功通過面試大有好處。