Java 設計模式之單例模式
1 簡介

單例模式保證一個類只有一個實例,并向外提供一個全局的訪問入口,單例類需自己實例化唯一的實例。Java 中 java.lang.Runtime 就是典型的單例模式實現例子,現實生活中的例子也比較多,比如:一個學校有一個校長、一個公司有一個董事長等。
優點:因為單例模式只生成一個實例,所以能夠節約系統資源、減少性能開銷,同時也能避免對共享資源的多重占用。
缺點:同樣因為只有一個實例,導致單例類的職責過重,與單一職責原則沖突,它沒有接口,不能繼承,不利于擴展。
2 實現方式
常見的單例模式實現方式大致有五種,分別為:餓漢式、懶漢式、雙重檢測鎖、靜態內部類、枚舉,通常我們需要保證單例模式的線程安全,下面來看一下如何通過這五種方式實現線程安全的單例模式。
2.1 餓漢式
餓漢式從字面上我們就能了解個大概:餓了就要馬上吃飯,這種模式在類加載時就初始化實例,缺點是容易產生垃圾對象,因為可能我們還沒有用到實例的時候,實例就已經被創建了;優點是線程安全,不用加鎖,效率高。示例如下:
public class Singleton { private static Singleton instance = new Singleton(); //將構造器設置為 private,禁止通過 new 實例化 private Singleton() {} public static Singleton getInstance() { return instance; } }
2.2 懶漢式
懶漢式就是懶加載,在首次調用時進行初始化,避免了內存被浪費問題,但這種方式在多線程情況下需要通過加鎖(如:synchronized )來保證線程安全,加鎖會影響效率,因此這種方式效率可能會比較低。示例如下:
public class Singleton { private static Singleton instance; private Singleton() {} public static Singleton getInstance() { synchronized(Singleton.class) { if (instance == null) { instance = new Singleton(); } } return instance; } }
2.3 雙重檢測鎖
這種方式采用雙鎖機制,在多線程情況下既能保證線程安全,同時又能保持較高的性能,當然這種方式實現會相對復雜了一點。示例如下:
public class Singleton { private volatile static Singleton instance; private Singleton (){} public static Singleton getInstance() { if (instance == null) { synchronized (Singleton.class) { if (instance == null) { instance = new Singleton(); } } } return instance; } }
從示例中我們可以看到,這種方式進行了兩次判斷,第一次是為了避免不要的實例創建,第二次是為了進行同步,避免多線程問題。instance = new Singleton() 創建時在 JVM 中可能會進行指令重排序,在多線程情況下會存在線程安全問題,使用 volatile 修飾 instance 解決該問題。
2.4 靜態內部類
這種方式和餓漢式一樣,通過 ClassLoader 的機制保證了線程安全,不同之處餓漢式一旦 Singleton 類被裝載了,那么 instance 就會被實例化,而這種方式只有內部類(SingletonInner)被主動使用時才會實例化單例對象;該方式可以達到雙重檢測鎖方式的效率,實現相對簡單一點,當然這種方式只適用于靜態域的情況,雙重檢測鎖方式可在實例域需要延遲初始化時使用。
示例如下:
public class Singleton { private static class SingletonInner { private static final Singleton instance = new Singleton(); } private Singleton() {} public static final Singleton getInstance() { return SingletonInner.instance; } }
2.5 枚舉
默認枚舉實例的創建是線程安全的,它自動支持序列化機制,可避免反射,防止多次實例化,因此在任何情況下都是單例的,它的實現也比較簡單,但由于 JDK1.5 之后才加入 enum,這種方式在實際工作中用的還是比較少。示例如下:
public enum Singleton { INSTANCE; public void getInstance() {} }
3 總結
懶漢式效率最低;
單例對象占用資源少,不需要延時加載,枚舉方式優于餓漢式;
單例對象占用資源多,需要延時加載,靜態內部類優于懶漢式。
Java
版權聲明:本文內容由網絡用戶投稿,版權歸原作者所有,本站不擁有其著作權,亦不承擔相應法律責任。如果您發現本站中有涉嫌抄襲或描述失實的內容,請聯系我們jiasou666@gmail.com 處理,核實后本網站將在24小時內刪除侵權內容。
版權聲明:本文內容由網絡用戶投稿,版權歸原作者所有,本站不擁有其著作權,亦不承擔相應法律責任。如果您發現本站中有涉嫌抄襲或描述失實的內容,請聯系我們jiasou666@gmail.com 處理,核實后本網站將在24小時內刪除侵權內容。