其實網上已經有很多介紹單例模式甚至是所有23種設計模式的了,都講得很好,所以這裡我不敢也不想說是為大家解疑惑,只是作為自己學習過程的筆記,以便以後進行查閱。
單例模式的概念就不在具體介紹,其核心本質就是一種物件建立的模式,用於產生乙個物件的具體例項,它可以確保乙個類物件只有乙個例項。這樣做的好處是:
(1)對於頻繁使用的物件,可以省略每次建立物件所花費的時間,這對於一些重量級物件而言,是一筆非常可觀的系統開銷。——時間方面
(2)由於new操作次數減少,因而對系統記憶體使用頻率也會降低,這將減輕gc壓力,縮短gc停頓時間。——記憶體方面
因此對於系統的關鍵元件和被頻繁使用的物件,使用單例模式可以有效改善系統的效能。
單例模式只有兩個參與者,分別是:
(1)單例類:提供單例的工廠,返回單例;
(2)使用類:獲取並使用單例類。
單例模式的結構圖:
下面由淺入深地介紹幾種實現單例模式的方式,我們這時應該在心裡默念:單例模式的核心在於通過乙個介面返回唯一的物件例項。
一、最簡單的實現方式
public class singleton
/** instance成員變數必須是static
*/private staticsingleton instance = new singleton();
/** getinstance函式必須是static
*/public staticsingletongetinstance()
}
優點:實現方式簡單,而且可靠。
缺點:唯一的不足是無法對instance例項做延遲載入。
假如單例建立過程緩慢,由於instance成員變數是static定義的,因此在jvm載入單例類時,單例物件就會被建立,如果此時,這個單例類在系統中還扮演其他角色,那麼在任何使用這個單例類的地方都會初始化這個單例變數,而不管是否會被用到。比如單例類作為string工廠,用於建立一些字串(該類既用於建立單例singleton,也用於建立string物件)。
public class singleton
/** instance成員變數必須是static
*/private static singleton instance = new singleton();
/** getinstance函式必須是static
*/public static singleton getinstance()
/** 模擬單例類扮演其它角色
*/public static void createstring()
}
這樣當使用singleton.createstring()執行任務是,程式輸出:
singleton is created!
createstring in singleton!
可以看到,雖然此時並沒有使用到單例類,但它還是被建立出來了,這就是我們開發人員最不願意看到的。為了解決這個問題,並以此提高系統在相關函式呼叫時的反應速度,就需要引入延遲載入機制。
二、延遲載入實現方式
public class lazysingleton
/** instance成員變數必須是static,此時先不要初始化,用到時再進行初始化
*/private static lazysingleton instance = null;
/** getinstance函式必須是static
*/public staticsynchronizedlazysingleton getinstance()
return instance;
}}
需要說明:getinstance()方法必須是同步的,否則在多執行緒環境下,當執行緒1正新建單例且完成賦值操作前,執行緒2可能判斷instance為null,故執行緒2也將啟動新建單例的程式,而導致多個例項被建立,故同步關鍵字是必須的。
優點:實現了延遲載入的功能;
缺點:和第一種方式相比,增加了同步關鍵字,導致在多執行緒環境中,它的時耗遠遠大於第一種方式。
@override
public void run()
system.out.println("spend:"+(system.currenttimemillis()-begintime));
}
開啟5個執行緒同時完成以上**,使用第一種型別單例耗時0ms,但使用第二種單例卻相對耗時390ms,效能至少差了2個數量級。開啟5個執行緒同時完成以上**,使用第一種型別單例耗時0ms,但使用第二種單例卻相對耗時390ms,效能至少差了2個數量級。開啟5個執行緒同時完成以上**,使用第一種型別單例耗時0ms,但使用第二種單例卻相對耗時390ms,效能至少差了2個數量級。開啟5個執行緒同時完成以上**,使用第一種型別單例耗時0ms,但使用第二種單例卻相對耗時390ms,效能至少差了2個數量級。開啟5個執行緒同時完成以上**,使用第一種型別單例耗時0ms,但使用第二種單例卻相對耗時390ms,效能至少差了2個數量級。開啟5個執行緒同時完成以上**,使用第一種型別單例耗時0ms,但使用第二種單例卻相對耗時390ms,效能至少差了2個數量級。開啟5個執行緒同時完成以上**,使用第一種型別單例耗時0ms,但使用第二種單例卻相對耗時390ms,效能至少差了2個數量級。開啟5個執行緒同時完成以上**,使用第一種型別單例耗時0ms,但使用第二種單例卻相對耗時390ms,效能至少差了2個數量級。
三、延遲載入改進實現方式
為了延遲載入而加入了同步關鍵字導致系統效能降低,有點得不償失,我們可以對延遲載入的方式進行改進:
public class staticsingleton
/** 引入內部類維護單例類例項的初始化,當staticsingleton被載入時其內部類不會被初始化,
* 故可以確保當staticsingleton類被載入jvm時,不會初始化單例類例項。
*/private static classsingletonholder
/** getinstance函式必須是static,該方法呼叫了內部類的instance變數,導致內部類的載入,
* 並對單例類例項進行了初始化
*/publicstaticstaticsingleton getinstance()
}
通過以上分析,由於單例類例項的建立是在類載入時完成的,故天生對多執行緒友好,從而getinstance方法不需要同步關鍵字。因此這種實現方式同時兼備以上兩種實現方式的優點:既可以實現延遲載入,也不必使用同步關鍵字。 java設計模式之單例模式
單位面試題目中有一道關於單例模式的題目.大多數參加筆試的同事都會寫出getinstance這個函式,但是當我問起什麼情況下需要使用單例 單例具體有什麼好處的時候 static函式也可以構建唯一例項,為什麼還需要單例.從使用單例的經驗來看,如下場景下,個人感覺應該使用單例 1.如果需要構建乙個工具類,...
java設計模式 之 單例模式
單例模式 有些類在程式執行過程中只需要儲存乙個例項,比如檔案管理類,音訊管理類,那麼我們如何實現乙個單例類呢?有以下幾點 1 定義乙個靜態變數 2 建構函式私有化 3 提供乙個public 靜態方法,獲取這個例項 4 一定要做執行緒同步 public static class singleton p...
Java設計模式之單例模式
說到單例模式 大家一定非常熟悉 這是最常見也是設計模式中相對簡單 好理解的設計模式 今天就跟大家掰一掰單例模式 單例模式確保某個類只有乙個例項 應用場景 執行緒池 快取 等物件常常被設計成單例 然而單例分兩種 1 惡漢式 2 懶漢式 我們先來看下 惡漢式 public class singleton...