1. 程式人生 > >java 設計模式 --singleton 單例模式

java 設計模式 --singleton 單例模式

Singleton 單例模式:

        有些物件只需要一個,比如:執行緒池、快取、對話方塊、處理偏好設定和登錄檔的物件、日誌物件,充當印表機、顯示卡等裝置的驅動程式的物件。

        這種型別的設計模式屬於建立型模式,它提供了一種建立物件的最佳方式。

        這種模式涉及到一個單一的類,該類負責建立自己的物件,同時確保只有單個物件被建立。這個類提供了一種訪問其唯一的物件的方式,可以直接訪問,不需要例項化該類的物件。

 

應用例項: 

1、要求生產唯一序列號。

2、Windows 是多程序多執行緒的,在操作一個檔案的時候,就不可避免地出現多個程序或執行緒同時操作一個檔案的現象,所以所有檔案的處理必須通過唯一的例項來進行。

3、一些裝置管理器常常設計為單例模式,比如一個電腦有兩臺印表機,在輸出的時候就要處理不能兩臺印表機列印同一個檔案。

4、WEB 中的計數器,不用每次重新整理都在資料庫里加一次,用單例先快取起來;

5、建立的一個物件需要消耗的資源過多,比如資料庫的連線等。

懶漢式

以下程式碼是懶漢式的執行緒安全 和不安全的 實現 和驗證:

public class SingletonTest {

	public static void main(String[] args) {
		SingletonTest singletonTest = new SingletonTest();

		// esay singleton
		// singletonTest.easySingleton();

		// singleton one  false 單執行緒  true 是多執行緒
//		singletonTest.singletonOneTest(true);
		
		// singleton two
		singletonTest.singletonOneTwo();
	}

	public void easySingleton() {
		// 不合法的建構函式
		// 編譯時錯誤:建構函式 SingleObject() 是不可見的
		// SingleObject object = new SingleObject();

		// 獲取唯一可用的物件
		SingletonObject object = SingletonObject.getInstance();

		// 顯示訊息
		object.test();
	}

	public void singletonOneTest(boolean isMultipe) {

		try {
			// 單執行緒
			if (!isMultipe) {
				Thread thread = new ThreadTest();
				thread.start();
			} else {
		        for (int i = 0; i < 200; i++) {
		        	Thread t4 = new ThreadTest();
		        	t4.start();
				}
			}
		} catch (Exception e) {
			System.out.println("執行緒異常了");
		}
	}
	
	public void singletonOneTwo() {
		for (int i = 0; i < 200; i++) {
        	Thread t4 = new ThreadTwoTest();
        	t4.start();
		}
	}
}

class ThreadTest extends Thread {
	private static int num = 0;
	public ThreadTest(){
        num++;
    }
	
	public void run() {
		try {
			System.out.println("建立的第"+num+"個執行緒");
			SingletonOne.getInstance();
		} catch (Exception e) {
			System.out.println("執行緒執行中斷異常");
		}
	}
}

class ThreadTwoTest extends Thread {
	private static int num = 0;
	public ThreadTwoTest(){
        num++;
    }
	
	public void run() {
		try {
			System.out.println("建立的第"+num+"個執行緒");
			SingletonTwo.getIntance();
		} catch (Exception e) {
			System.out.println("執行緒執行中斷異常");
		}
	}
}
/**
 * 懶漢式,執行緒不安全
 * 這種方式是最基本的實現方式;
 * 這種實現最大的問題就是不支援多執行緒。
 * 因為沒有加鎖 synchronized,所以嚴格意義上它並不算單例模式。
 * 這種方式 lazy loading 很明顯,不要求執行緒安全,在多執行緒不能正常工作。
 */
public class SingletonOne {
	private static int count = 0;
	//定義物件
	private static SingletonOne instance = null;
	//私有化初始方法
	private SingletonOne(){}
	
	//例項化物件
	public static SingletonOne getInstance(){
		try {
			if(null == instance) {
				count ++;
				System.out.println("Singleton 物件第 " + count + "次建立。");
				instance = new SingletonOne();
			}
		} catch (Exception e) {
			System.err.println("執行緒異常");
		}
		return instance;
	}
}
/**
 * 懶漢式,執行緒安全
 * 這種方式具備很好的 lazy loading,能夠在多執行緒中很好的工作,但是,效率很低,99% 情況下不需要同步。
 * 優點:第一次呼叫才初始化,避免記憶體浪費
 * 缺點:必須加鎖 synchronized 才能保證單例,但加鎖會影響效率。
 */
public class SingletonTwo {
	private static int count = 0;
	private static SingletonTwo instance = null;
	private SingletonTwo() {}
	
	public static synchronized  SingletonTwo getIntance() {
		try {
			if(null == instance) {
				count ++;
				System.out.println("Singleton 物件第 " + count + "次建立。");
				instance = new SingletonTwo();
			}
		} catch (Exception e) {
			System.err.println("執行緒異常");
		}
		return instance;
	}
}

 

3.餓漢式

常用的 一種方式 ,在類載入的時候就開始初始化,所以這種方式很耗記憶體。

public class Singleton {  
    private static Singleton instance = new Singleton();  
    private Singleton (){}  
    public static Singleton getInstance() {  
    return instance;  
    }  
}

 

4、雙檢鎖/雙重校驗鎖(DCL,即 double-checked locking)

public class Singleton {  
    private volatile static Singleton singleton;  
    private Singleton (){}  
    public static Singleton getSingleton() {  
    if (singleton == null) {  
        synchronized (Singleton.class) {  
        if (singleton == null) {  
            singleton = new Singleton();  
        }  
        }  
    }  
    return singleton;  
    }  
}

 

總結下:

第一第二中肯定是建議少用的,第三種餓漢式 感覺還可以,第四種 雙檢鎖 就更穩定點。