Java中的四種單例模式淺析
前言
近期在做支付,一開(kāi)始圖省事,也是為了調(diào)試方便,支付的alipayClient和tradeService都是使用的時(shí)候去拿,這樣就會(huì)導(dǎo)致創(chuàng)建多次。為了節(jié)省資源,統(tǒng)一配置成單例模式。
什么是單例
Singleton(單例)是設(shè)計(jì)模式的一種,為了保證一個(gè)類(lèi)僅有一個(gè)實(shí)例,并提供一個(gè)訪問(wèn)它的全局訪問(wèn)點(diǎn)。
單例特點(diǎn)
- 單例類(lèi)確保自己只有一個(gè)實(shí)例(構(gòu)造函數(shù)私有:不被外部實(shí)例化,也不被繼承)。
- 單例類(lèi)必須自己創(chuàng)建自己的實(shí)例。
- 單例類(lèi)必須為其他對(duì)象提供唯一的實(shí)例。
單例應(yīng)用
資源管理器,回收站,打印機(jī)資源,線程池,緩存,配置信息類(lèi),管理類(lèi),控制類(lèi),門(mén)面類(lèi),代理類(lèi)通常被設(shè)計(jì)為單例類(lèi)。如果程序有多個(gè)類(lèi)加載器又同時(shí)使用單例模式就要保證單例的唯一性了。
實(shí)現(xiàn)方式
餓漢式
/**
* 餓漢式
*
*/
public class Singleton {
private static Singleton instance = new Singleton();
//私有的默認(rèn)構(gòu)造子,保證外界無(wú)法直接實(shí)例化
private Singleton() {}
//提供全局訪問(wèn)點(diǎn)獲取唯一的實(shí)例
public static Singleton getInstance() {
return instance;
}
}
如果開(kāi)銷(xiāo)比較大,希望用到時(shí)才創(chuàng)建就要考慮延遲實(shí)例化,就要用后面的方法了。
懶漢式
/**
* 懶漢式
*/
public class Singleton {
private static Singleton instance;
//私有的默認(rèn)構(gòu)造子,保證外界無(wú)法直接實(shí)例化
private Singleton() {}
public static synchronized Singleton getInstance() {
if(instance==null){
instance = new Singleton();
}
return instance;
}
}
懶漢式(雙重鎖)
“雙檢鎖”(Double-Checked Lock)盡量將”加鎖”推遲,只在需要時(shí)”加鎖”(僅適用于java 5.0 以上版本,volatile保證原子操作)。
happens-before:”什么什么一定在什么什么之前運(yùn)行”,也就是保證順序性。
現(xiàn)在的CPU有亂序執(zhí)行的能力(也就是指令會(huì)亂序或并行運(yùn)行,可以不按我們寫(xiě)代碼的順序執(zhí)行內(nèi)存的存取過(guò)程),并且多個(gè)CPU之間的緩存也不保證實(shí)時(shí)同步,只有上面的happens-before所規(guī)定的情況下才保證順序性。
JVM能夠根據(jù)CPU的特性(CPU的多級(jí)緩存系統(tǒng)、多核處理器等)適當(dāng)?shù)闹匦屡判驒C(jī)器指令,使機(jī)器指令更符合CPU的執(zhí)行特點(diǎn),最大限度的發(fā)揮機(jī)器的性能.
如果沒(méi)有volatile修飾符則可能出現(xiàn)一個(gè)線程t1的B操作和另一線程t2的C操作之間對(duì)instance的讀寫(xiě)沒(méi)有happens-before,可能會(huì)造成的現(xiàn)象是t1的B操作還沒(méi)有完全構(gòu)造成功,但t2的C已經(jīng)看到instance為非空,這樣t2就直接返回了未完全構(gòu)造的instance的引用,t2想對(duì)instance進(jìn)行操作就會(huì)出問(wèn)題。
volatile 的功能:
- 避免編譯器將變量緩存在寄存器里
- 避免編譯器調(diào)整代碼執(zhí)行的順序
優(yōu)化器在用到這個(gè)變量時(shí)必須每次都小心地重新讀取這個(gè)變量的值,而不是使用保存在寄存器里的備份
/**
* 懶漢式(雙重鎖)
*/
public class Singleton {
//使用 volatile 保證可見(jiàn)性
private volatile static Singleton instance;
//私有的默認(rèn)構(gòu)造子,保證外界無(wú)法直接實(shí)例化
private Singleton() {}
public static Singleton getInstance() {
if(instance==null){
synchronized(Singleton.class){
if(instance==null){
instance = new Singleton();
}
}
}
return instance;
}
}
內(nèi)部類(lèi)
/**
* 內(nèi)部類(lèi)
*/
public class Singleton {
//私有的默認(rèn)構(gòu)造子,保證外界無(wú)法直接實(shí)例化
private Singleton() {}
/**
* 類(lèi)級(jí)的內(nèi)部類(lèi),也就是靜態(tài)的成員式內(nèi)部類(lèi),該內(nèi)部類(lèi)的實(shí)例與外部類(lèi)的實(shí)例
* 沒(méi)有綁定關(guān)系,而且只有被調(diào)用到才會(huì)裝載,從而實(shí)現(xiàn)了延遲加載
*/
private static class SingletonHolder{
/**
* 靜態(tài)初始化器,由JVM來(lái)保證線程安全
*/
private static Singleton instance = new Singleton();
}
public static Singleton getInstance() {
return SingletonHolder.instance;
}
}
總結(jié)
以上就是這篇文章的全部?jī)?nèi)容了,希望本文的內(nèi)容對(duì)大家的學(xué)習(xí)或者工作能帶來(lái)一定的幫助,如果有疑問(wèn)大家可以留言交流,謝謝大家對(duì)腳本之家的支持。
相關(guān)文章
SpringCloud @FeignClient參數(shù)的用法解析
這篇文章主要介紹了SpringCloud @FeignClient參數(shù)的用法,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-10-10
Springboot詳解如何實(shí)現(xiàn)SQL注入過(guò)濾器過(guò)程
這篇文章主要介紹了基于springboot實(shí)現(xiàn)SQL注入過(guò)濾器,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2022-06-06
微信游戲打飛機(jī)游戲制作(java模擬微信打飛機(jī)游戲)
java模擬微信打飛機(jī)游戲,大家參考使用吧2013-12-12
SpringBoot整合RabbitMQ, 實(shí)現(xiàn)生產(chǎn)者與消費(fèi)者的功能
這篇文章主要介紹了SpringBoot整合RabbitMQ, 實(shí)現(xiàn)生產(chǎn)者與消費(fèi)者的功能,幫助大家更好得理解和學(xué)習(xí)使用SpringBoot框架,感興趣的朋友可以了解下2021-03-03
Java日常練習(xí)題,每天進(jìn)步一點(diǎn)點(diǎn)(44)
下面小編就為大家?guī)?lái)一篇Java基礎(chǔ)的幾道練習(xí)題(分享)。小編覺(jué)得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧,希望可以幫到你2021-07-07
Java實(shí)現(xiàn)二分搜索樹(shù)的示例代碼
二分搜索樹(shù)是一顆二叉樹(shù),二分搜索樹(shù)每個(gè)節(jié)點(diǎn)的左子樹(shù)的值都小于該節(jié)點(diǎn)的值,每個(gè)節(jié)點(diǎn)右子樹(shù)的值都大于該節(jié)點(diǎn)的值。本文將利用Java實(shí)現(xiàn)二分搜索樹(shù),需要的可以參考一下2022-03-03
Java中java.sql.SQLException異常的正確解決方法(親測(cè)有效!)
SQLException是在Java中處理數(shù)據(jù)庫(kù)操作過(guò)程中可能發(fā)生的異常,通常是由于底層數(shù)據(jù)庫(kù)操作錯(cuò)誤或違反了數(shù)據(jù)庫(kù)規(guī)則而引起的,下面這篇文章主要給大家介紹了關(guān)于Java中java.sql.SQLException異常的正確解決方法,需要的朋友可以參考下2024-01-01

