java設(shè)計(jì)模式-單例模式實(shí)現(xiàn)方法詳解
單例模式,屬于創(chuàng)建類型的一種常用的軟件設(shè)計(jì)模式。通過單例模式的方法創(chuàng)建的類在當(dāng)前進(jìn)程中只有一個(gè)實(shí)例(根據(jù)需要,也有可能一個(gè)線程中屬于單例,如:僅線程上下文內(nèi)使用同一個(gè)實(shí)例)。就是采取一定的方法保證在整個(gè)的軟件系統(tǒng)中,對(duì)某個(gè)類只能存在一個(gè)對(duì)象實(shí)例,并且該類只提供一個(gè)取得其對(duì)象實(shí)例的方法(靜態(tài)方法)。
就是類在內(nèi)存中只能存在一個(gè)實(shí)例對(duì)象
餓漢式
所謂餓漢式,就是直接創(chuàng)建出類的實(shí)例化,然后用private私有化,對(duì)外只用靜態(tài)方法暴露。
靜態(tài)變量
步驟
- 構(gòu)造器私有化
- 類的內(nèi)部創(chuàng)建對(duì)象
- 向外暴露一個(gè)靜態(tài)的公共方法
| 優(yōu)點(diǎn) | 缺點(diǎn) |
|---|---|
| 寫法簡單,在類裝載的時(shí)完成實(shí)例化,避免了線程同步問題 | 類裝載時(shí)完成實(shí)例化,沒有達(dá)到LazyLoading的效果,若該實(shí)例從未使用,則會(huì)造成內(nèi)存浪費(fèi) |
class Singleton {
//私有化構(gòu)造器
private Singleton() {
}
//內(nèi)部創(chuàng)建對(duì)象實(shí)例
private final static Singleton instance = new Singleton();
//對(duì)外公有的靜態(tài)方法
public static Singleton getInstance() {
return instance;
}
}
靜態(tài)代碼塊
將類的實(shí)例化放到靜態(tài)代碼塊中的寫法,基本同上。
class Singleton { //靜態(tài)代碼塊
//私有化構(gòu)造器
private Singleton() {}
//內(nèi)部創(chuàng)建對(duì)象實(shí)例
private static Singleton instance;
static { // 在靜態(tài)代碼塊中,創(chuàng)建單例對(duì)象
instance = new Singleton();
}
//對(duì)外公有的靜態(tài)方法
public static Singleton getInstance() {
return instance;
}
}
測試代碼(后面都可使用這個(gè)測試代碼,不在贅述運(yùn)行截圖,可以自己試試):
public static void main(String[] args) {
Singleton instance1 = Singleton.getInstance();
Singleton instance2 = Singleton.getInstance();
System.out.println(instance1 == instance2);
System.out.println("instance1.hashCode=" + instance1.hashCode());
System.out.println("instance2.hashCode=" + instance2.hashCode());
}

懶漢式
所謂懶漢式,就是在需要調(diào)用的時(shí)候再創(chuàng)建類的實(shí)例化。
線程不安全
起到了懶加載效果,但是只能在單線程使用,多線程會(huì)不安全,因?yàn)楫?dāng)多個(gè)線程并發(fā)同時(shí)判斷instance為空時(shí),就會(huì)相應(yīng)的實(shí)例化多個(gè)對(duì)象。
class Singleton { //線程不安全
private static Singleton instance;
private Singleton() {}
public static Singleton getInstance() { //調(diào)用時(shí)才實(shí)例化對(duì)象,懶漢式
if(instance == null) {
instance = new Singleton();
}
return instance;
}
}
線程安全
上面線程不安全,那上鎖不就好了,使用synchronized關(guān)鍵字。
這樣雖然解決了線程安全,但其實(shí)實(shí)例化操作只做一次,而獲取實(shí)例(即getInstance)的操作是很多次的,把調(diào)用的方法加上同步,會(huì)大大降低效率。
class Singleton { //線程安全
private static Singleton instance;
private Singleton() {}
//synchronized同步處理
public static synchronized Singleton getInstance() {
if(instance == null) {
instance = new Singleton();
}
return instance;
}
}
雙重檢查
上面代碼效率低,那在同步前判斷一下有沒有實(shí)例化不就好了,若沒有實(shí)例化則用同步方法new一個(gè),否則直接return即可。即所謂的雙重檢查。
需要用到關(guān)鍵字volatile,防止指令重排。如果不用volatile關(guān)鍵字,就會(huì)和線程不安全情形一樣,在if判斷那會(huì)有并發(fā)。
class Singleton { //雙重檢查
private static volatile Singleton instance;
private Singleton() {}
public static synchronized Singleton getInstance() {
if(instance == null) { //判斷是否實(shí)例化
synchronized (Singleton.class) {
if(instance == null) {
instance = new Singleton();
}
}
}
return instance; //否則直接return
}
}
這樣既實(shí)現(xiàn)了懶加載,又保證了線程安全。
靜態(tài)內(nèi)部類
靜態(tài)內(nèi)部類在外部類裝載時(shí)不會(huì)實(shí)例化,當(dāng)調(diào)用的時(shí)候才會(huì)裝載并實(shí)例化,且JVM保證了其裝載時(shí)的線程安全性。也能保證懶加載和線程安全,有點(diǎn)像自帶版的雙重檢查。
class Singleton {
private static volatile Singleton instance;
private Singleton() {}
//靜態(tài)內(nèi)部類,包含一個(gè)靜態(tài)屬性:Singleton
private static class SingletonInstance {
private static final Singleton INSTANCE = new Singleton();
}
//對(duì)外公有的靜態(tài)方法,直接返回SingletonInstance.INSTANCE
public static synchronized Singleton getInstance() {
return SingletonInstance.INSTANCE;
}
}
枚舉
其實(shí),使用枚舉也能實(shí)現(xiàn)單例模式,不僅能避免多線程同步問題,也能防止反序列化重新創(chuàng)建新的對(duì)象。
enum Singleton {
INSTANCE; //屬性
public void say() {
System.out.println("記得三連~");
}
}
對(duì)應(yīng)測試:
public static void main(String[] args) {
Singleton instance1 = Singleton.INSTANCE;
Singleton instance2 = Singleton.INSTANCE;
System.out.println(instance1 == instance2);
System.out.println(instance1.hashCode());
System.out.println(instance2.hashCode());
instance1.say();
}

總結(jié)
單例模式使用的場景:
需要頻繁的進(jìn)行創(chuàng)建和銷毀的對(duì)象創(chuàng)建對(duì)象時(shí)耗時(shí)過多或耗費(fèi)資源過多(重量級(jí)對(duì)象)經(jīng)常用到的對(duì)象、工具類對(duì)象、頻繁訪問數(shù)據(jù)庫或文件的對(duì)象(數(shù)據(jù)源、session工廠)
本篇文章就到這里了,希望能給你帶來幫助,也希望您能夠多多關(guān)注腳本之家的更多內(nèi)容!
相關(guān)文章
由淺到深帶你詳談Java實(shí)現(xiàn)數(shù)組擴(kuò)容的三種方式
這篇文章主要詳細(xì)介紹了Java實(shí)現(xiàn)數(shù)組擴(kuò)容的三種方式,新建一個(gè)數(shù)組,把原來數(shù)組的內(nèi)容搬到新數(shù)組中,使用system.arraycopy(),使用java.util.Arrays.copyOf()這三種方式,具有一定的參考價(jià)值,需要的朋友可以借鑒一下2023-06-06
Springboot實(shí)現(xiàn)人臉識(shí)別與WebSocket長連接的實(shí)現(xiàn)代碼
這篇文章主要介紹了Springboot實(shí)現(xiàn)人臉識(shí)別與WebSocket長連接的實(shí)現(xiàn),本文通過示例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友參考下吧2023-11-11
Mybatis Properties 配置優(yōu)先級(jí)詳解
這篇文章主要介紹了Mybatis Properties 配置優(yōu)先級(jí),具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-07-07
SpringBoot實(shí)現(xiàn)文件壓縮處理詳解
在工作我們經(jīng)常會(huì)出現(xiàn)有多個(gè)文件,為了節(jié)省資源會(huì)將多個(gè)文件放在一起進(jìn)行壓縮處理,本文將使用SpringBoot實(shí)現(xiàn)文件壓縮處理,感興趣的可以了解下2024-11-11
JavaSE實(shí)現(xiàn)文件壓縮與解壓縮的技巧分享
我們?cè)谌粘?shí)際開發(fā)中,對(duì)于文件壓縮和解壓縮場景,是非常常見的操作,本文詳細(xì)介紹JavaSE中文件壓縮和解壓縮的實(shí)現(xiàn)方法,包括源代碼解析、應(yīng)用場景案例、優(yōu)缺點(diǎn)分析、案例演示、文末總結(jié)等等,請(qǐng)同學(xué)們耐心閱讀2024-03-03
在Java Spring框架中使用的設(shè)計(jì)模式有哪些
面試中常會(huì)被問道Spring框架使用了哪些設(shè)計(jì)模式?關(guān)于這個(gè)問題本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2021-09-09
java使用Validation進(jìn)行數(shù)據(jù)校驗(yàn)的方式總結(jié)
在Java中提供了一系列的校驗(yàn)方式,下面這篇文章主要給大家介紹了關(guān)于java使用Validation進(jìn)行數(shù)據(jù)校驗(yàn)的相關(guān)資料,文中通過實(shí)例代碼介紹的非常詳細(xì),需要的朋友可以參考下2023-06-06
springboot實(shí)現(xiàn)后臺(tái)上傳圖片(工具類)
這篇文章主要為大家詳細(xì)介紹了springboot實(shí)現(xiàn)后臺(tái)上傳圖片,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2021-04-04

