單列中的四種實現方式
方式一:普通的餓漢式和懶漢式單例模式
三部曲:
(1)私有化構造方法 (2)私有化靜態本類物件作為屬性 (3)提供公有靜態方法獲取本類物件
1.普通的餓漢式(靜態的內部)
public class Client { public static void main(String[] args) { Singleton.getInstance(); } static class Singleton { private static final Singleton instance = new Singleton(); private Singleton(){} public static Singleton getInstance(){ return instance; } } }
2.餓漢式靜態程式碼塊單例模式
//餓漢式靜態程式碼塊單例模式 public class HungryStaticSingleton { private static final HungryStaticSingleton instance; static { instance = new HungryStaticSingleton(); } private HungryStaticSingleton(){} public static HungryStaticSingleton getInstance(){ return instance; } }
3.餓漢式靜態程式碼塊單例模式
/** * 優點:執行效率高,效能高,沒有任何的鎖 * 缺點:某些情況下,可能會造成記憶體浪費 */ //餓漢式靜態程式碼塊單例模式 public class HungrySingleton { private static final HungrySingleton instance = new HungrySingleton(); private HungrySingleton(){} public static HungrySingleton getInstance(){ return instance; } }
二:懶漢式
1.懶漢式單例模式在外部需要使用的時候才進行例項化,這種是執行緒不安全的,如果多個執行緒同時併發訪問,假設多個執行緒同時都進入到了 if(instance == null){}條件判斷裡面,那麼就會同時建立多個物件。
/** * 優點:節省了記憶體,執行緒安全 * 缺點:效能低 */ //懶漢式單例模式在外部需要使用的時候才進行例項化 public class LazySimpleSingletion { //靜態塊,公共記憶體區域 private static LazySimpleSingletion instance; private LazySimpleSingletion(){} public synchronized static LazySimpleSingletion getInstance(){ if(instance == null){ instance = new LazySimpleSingletion(); } return instance; } }
2.單次檢查機制(使用類鎖),這種也是有缺點的,使用的 synchronized 關鍵字,嚴重的影響了效能.
public class Singleton { private static Singleton instance = null; public static Singleton getInstance() { synchronized (Singleton.class) { if(null == instance) { instance = new Singleton(); } } return instance; } }
3.利用雙重檢查機制(DCL) ,保證了執行緒的安全
/** * 優點:效能高了,執行緒安全了 * 缺點:可讀性難度加大,不夠優雅 */ public class LazyDoubleCheckSingleton { private volatile static LazyDoubleCheckSingleton instance; private LazyDoubleCheckSingleton(){} public static LazyDoubleCheckSingleton getInstance(){ //檢查是否要阻塞 if (instance == null) { synchronized (LazyDoubleCheckSingleton.class) { //檢查是否要重新建立例項 if (instance == null) { instance = new LazyDoubleCheckSingleton(); //指令重排序的問題 } } } return instance; } }
4.自認為史上最牛的單例模式的實現方式 (這裡有個技術上的高深的點技術基礎點,說到底還是技術的基礎和本質)----->>>> 利用了Java本身語法特點,內部類預設不載入
/* ClassPath : LazyStaticInnerClassSingleton.class LazyStaticInnerClassSingleton$LazyHolder.class 優點:寫法優雅,利用了Java本身語法特點,效能高,避免了記憶體浪費,不能被反射破壞 缺點:不優雅 */ //這種形式兼顧餓漢式單例模式的記憶體浪費問題和synchronized的效能問題 //完美地遮蔽了這兩個缺點 //自認為史上最牛的單例模式的實現方式 public class LazyStaticInnerClassSingleton { //使用LazyInnerClassGeneral的時候,預設會先初始化內部類 //如果沒使用,則內部類是不載入的 private LazyStaticInnerClassSingleton(){ if(LazyHolder.INSTANCE != null){ throw new RuntimeException("不允許建立多個例項"); } } //每一個關鍵字都不是多餘的,static是為了使單例的空間共享,保證這個方法不會被重寫、過載 private static LazyStaticInnerClassSingleton getInstance(){ //在返回結果以前,一定會先載入內部類 return LazyHolder.INSTANCE; } //利用了Java本身語法特點,內部類預設不載入 private static class LazyHolder{ private static final LazyStaticInnerClassSingleton INSTANCE = new LazyStaticInnerClassSingleton(); } }
5.列舉法
public enum EnumSingleton { INSTANCE; private Object data; public Object getData() { return data; } public void setData(Object data) { this.data = data; } public static EnumSingleton getInstance(){return INSTANCE;} }
6.序列化一個單列物件
import java.io.Serializable; public class SeriableSingleton implements Serializable { //序列化 //把記憶體中物件的狀態轉換為位元組碼的形式 //把位元組碼通過IO輸出流,寫到磁碟上 //永久儲存下來,持久化 //反序列化 //將持久化的位元組碼內容,通過IO輸入流讀到記憶體中來 //轉化成一個Java物件 public final static SeriableSingleton INSTANCE = new SeriableSingleton(); private SeriableSingleton(){} public static SeriableSingleton getInstance(){ return INSTANCE; } private Object readResolve(){ return INSTANCE;} }
7.手動建立一個單列物件(根據類名來建立)
public class ContainerSingleton { private ContainerSingleton(){} private static Map<String,Object> ioc = new ConcurrentHashMap<String, Object>(); public static Object getInstance(String className){ Object instance = null; if(!ioc.containsKey(className)){ try { instance = Class.forName(className).newInstance(); ioc.put(className, instance); }catch (Exception e){ e.printStackTrace(); } return instance; }else{ return ioc.get(className); } } }
8.ThreadLocal設定單列
public class ThreadLocalSingleton { private static final ThreadLocal<ThreadLocalSingleton> threadLocaLInstance = new ThreadLocal<ThreadLocalSingleton>(){ @Override protected ThreadLocalSingleton initialValue() { return new ThreadLocalSingleton(); } }; private ThreadLocalSingleton(){} public static ThreadLocalSingleton getInstance(){ return threadLocaLInstance.get(); } }