JAVA設計模式之單例模式

2021-07-05 17:22:17 字數 3403 閱讀 8817

其實網上已經有很多介紹單例模式甚至是所有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...