單例模式是Java 中最經常使用的設計模式,也是面試中常常考察的。java
<圖解設計模式> 書本上的示例代碼,在class內有一個靜態的變量直接賦值,在類加載的時候就初始化。缺點是有點浪費內存。由於類加載的時候是單線程,保證單例和線程安全。面試
public class Singleton1 { private static Singleton1 singleton1 = new Singleton1(); private Singleton1() { System.out.println("生成了一個實例."); } public static Singleton1 getInstance() { return singleton1; } }
延遲初始化實例,可是爲了保證線程安全,getInstance須要加鎖。設計模式
public class Singleton2 { private static Singleton2 singleton2 = null; private Singleton2() { System.out.println("生成了一個實例."); } public static synchronized Singleton2 getInstance() { if (singleton2 == null){ singleton2 = new Singleton2(); } return singleton2; } }
在方法上加鎖synchronized,效率比較低,爲了提升效率在getInstance方法內部加鎖。鎖住的代碼範圍越小,所等待的時間越少。安全
public class Singleton3 { private static Singleton3 instance = null; private Singleton3() { System.out.println("生成了一個實例."); } public static Singleton3 getInstance() { if (instance == null){ synchronized (Singleton3.class){ if (instance == null) { instance = new Singleton3(); } } } return instance; } }
這種方式一樣利用了 classloder 機制來保證初始化 instance 時只有一個線程,它跟標準版本不一樣的是:標準版本只要 Singleton 類被裝載了,那麼 instance 就會被實例化(沒有達到 lazy loading 效果),而這種方式是 Singleton 類被裝載了,instance 不必定被初始化。由於 SingletonHolder 類沒有被主動使用,只有顯示經過調用 getInstance 方法時,纔會顯示裝載 SingletonHolder 類,從而實例化 instance。想象一下,若是實例化 instance 很消耗資源,因此想讓它延遲加載,另一方面,又不但願在 Singleton 類加載時就實例化,由於不能確保 Singleton 類還可能在其餘的地方被主動使用從而被加載,那麼這個時候實例化 instance 顯然是不合適的。這個時候,這種方式相比標準版本就顯得很合理。線程
public class Singleton4 { private static class SingletonHolder { private static final Singleton4 INSTANCE = new Singleton4(); } private Singleton4 (){} public static final Singleton4 getInstance() { return SingletonHolder.INSTANCE; } }