設計模式—singleton(單例模式)


單例模式

  • 單例設計模式屬於創建型模式,它提供了一種創建對象的最佳方式。這種模式涉及到一個單一的類,該類負責創建自己的對象,同時確保只有單個對象被創建。

    這個類提供了一種訪問其唯一的對象的方式,可以直接訪問,不需要實例化該類的對象。

應用實例

  • Windows是多進程多線程的,通過唯一的實例來操作一個文件,避免地出現多個進程或線程同時操作一個文件的現象。

  • 一些設備管理器常常設計為單例模式(如一個電腦有兩台打印機,在輸出的時候就要處理不能兩台打印機打印同一個文件)。

使用場景

  • 要求生產唯一序列號。

  • WEB 中的計數器,不用每次刷新都在數據庫里加一次,用單例先緩存起來。

  • 創建的一個對象需要消耗的資源過多,比如 I/O 與數據庫的連接等。

單例實現

  • 方式一

方式二

  • 改進了方式一的缺點,但同時帶來了線程安全問題

  • 假設有兩個線程,線程1到第9行判斷完實例是否為空時(還沒到new一個實例),線程2也到了判斷實例是否為空的位置,

    因為線程1還沒創建實例,INSTANCE仍為空,線程2創建完一個實例后,線程1繼續執行也創建了一個實例。

方式三

  • 通過synchronized加鎖,解決方式二的線程安全問題,但也帶來了效率下降。

  • 通過加鎖,鎖定了Mgr03.class對象,因此輸出的hashcode是相同的。

方式四

  • 雙重校驗鎖,完美的單例模式寫法之一。

  • 如果只有外層判斷,就會出現線程安全問題(如同方式二)。

方式五

  • 靜態內部類方式,解決了方式一的問題,達到了按需初始化的目的,是完美的單例模式之一。

方式六

  • 通過枚舉實現單例

public class Mgr05 {
	private Mgr05() {};
	//類Mgr05加載時,內部類不會加載
	private static class Mgr05Holder{
		private final static Mgr05 INSTANCE=new Mgr05();
	}
	//調用getInstance(),類Mgr05Holder加載
	public static Mgr05 getInstance() {return Mgr05Holder.INSTANCE;};
	public static void main(String[] args) {
		for(int i=0;i<200;i++) {
			new Thread(()->{
				System.out.println(Mgr05.getInstance().hashCode());
			}).start();
		}
	}
}

public class Mgr04 {
	private static volatile Mgr04 INSTANCE;
	private Mgr04() {};
	public static synchronized Mgr04 getInstance() {
		if(INSTANCE==null) {//雙重校驗鎖
			synchronized (Mgr04.class) {
				if(INSTANCE==null) {
					try {
						Thread.sleep(10);
					}catch(InterruptedException e) {
						e.printStackTrace();
					}
				}
			}
			INSTANCE=new Mgr04();	
		}
		return INSTANCE;
	}
	public void c() {System.out.println("c");}
	public static void main(String[] args) {
		for(int i=0;i<200;i++) {
			new Thread(()->{
				System.out.println(Mgr04.getInstance().hashCode());
			}).start();
		}
}
}


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM