java 設計模式 --singleton 單例模式
阿新 • • 發佈:2018-11-13
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;
}
}
總結下:
第一第二中肯定是建議少用的,第三種餓漢式 感覺還可以,第四種 雙檢鎖 就更穩定點。