柚子快報(bào)邀請(qǐng)碼778899分享:開(kāi)發(fā)語(yǔ)言 【Java】單例模式
柚子快報(bào)邀請(qǐng)碼778899分享:開(kāi)發(fā)語(yǔ)言 【Java】單例模式
單例模式是面試中??嫉脑O(shè)計(jì)模式之一 在面試中,面試官常常會(huì)要求寫(xiě)出兩種類(lèi)型的單例模式并解釋原理 本文中,將從0到1的介紹單例模式究竟是什么
文章目錄
?一、什么是設(shè)計(jì)模式??二、單例模式是什么??三、單例模式的類(lèi)型**1.餓漢式**2.懶漢式3.優(yōu)化懶漢式4.指令重排5.完整代碼
?一、什么是設(shè)計(jì)模式?
設(shè)計(jì)模式(Design pattern)是一套被反復(fù)使用、多數(shù)人知曉的、經(jīng)過(guò)分類(lèi)編目的、代碼設(shè)計(jì)經(jīng)驗(yàn)的總結(jié)。使用設(shè)計(jì)模式是為了可重用代碼、讓代碼更容易被他人理解、保證代碼可靠性。 毫無(wú)疑問(wèn),設(shè)計(jì)模式于己于他人于系統(tǒng)都是多贏的,設(shè)計(jì)模式使代碼編制真正工程化,設(shè)計(jì)模式是軟件工程的基石,如同大廈的一塊塊磚石一樣。項(xiàng)目中合理的運(yùn)用設(shè)計(jì)模式可以完美的解決很多問(wèn)題,每種模式在現(xiàn)在中都有相應(yīng)的原理來(lái)與之對(duì)應(yīng),每一個(gè)模式描述了一個(gè)在我們周?chē)粩嘀貜?fù)發(fā)生的問(wèn)題,以及該問(wèn)題的核心解決方案,這也是它能被廣泛應(yīng)用的原因。簡(jiǎn)單說(shuō):
模式:在某些場(chǎng)景下,針對(duì)某類(lèi)問(wèn)題的某種通用的解決方案。
場(chǎng)景:項(xiàng)目所在的環(huán)境
問(wèn)題:約束條件,項(xiàng)目目標(biāo)等
解決方案:通用、可復(fù)用的設(shè)計(jì),解決約束達(dá)到目標(biāo)。
用生活中的事務(wù)來(lái)介紹:
設(shè)計(jì)模式好?象棋中的 “棋譜”. 紅?當(dāng)頭炮, ???來(lái)跳. 針對(duì)紅?的?些?法, ??應(yīng)招的時(shí)候有?些固定的套路. 按照套路來(lái)?局勢(shì)就不會(huì)吃虧.
?二、單例模式是什么?
單例模式是指在內(nèi)存中只會(huì)創(chuàng)建且僅創(chuàng)建一次對(duì)象的設(shè)計(jì)模式。在程序中多次使用同一個(gè)對(duì)象且作用相同時(shí),為了防止頻繁地創(chuàng)建對(duì)象使得內(nèi)存飆升,單例模式可以讓程序僅在內(nèi)存中創(chuàng)建一個(gè)對(duì)象,讓所有需要調(diào)用的地方都共享這一單例對(duì)象。
簡(jiǎn)單概括:
單例模式能保證某個(gè)類(lèi)在程序中只存在唯??份實(shí)例,而不會(huì)創(chuàng)建出多個(gè)實(shí)例.
?三、單例模式的類(lèi)型
單例模式具體的實(shí)現(xiàn)?式有很多. 最常?的是 “餓漢” 和 “懶漢” 兩種.
餓漢式:在類(lèi)加載過(guò)程中就創(chuàng)建了實(shí)例。懶漢式:在真正需要使用時(shí),才會(huì)創(chuàng)建實(shí)例。
1.餓漢式
class Singleton{
private static Singleton instance = new Singleton();
public static Singleton getInstance(){
return instance;
}
private Singleton(){}
}
類(lèi)在加載時(shí),就會(huì)創(chuàng)建一個(gè)實(shí)例。在調(diào)用時(shí),之間返回這一實(shí)例就好。
可以簡(jiǎn)單的認(rèn)為,在程序啟動(dòng)時(shí)就創(chuàng)建了實(shí)例。
2.懶漢式
class Singletonlazy{
public static Singletonlazy instance = null;
public Singletonlazy getInstance(){
if ( instance == null){
instance = new Singletonlazy();
}
return instance;
}
private Singletonlazy(){}
}
這是一段存在些許問(wèn)題的代碼,不過(guò)可以直觀的感受到兩者之間的區(qū)別。
在接下來(lái),會(huì)對(duì)如上懶漢式代碼進(jìn)行優(yōu)化。
3.優(yōu)化懶漢式
我們先將懶漢式代碼放置如下
class Singletonlazy{
public static Singletonlazy instance = null;
public Singletonlazy getInstance(){
if ( instance == null){
instance = new Singletonlazy();
}
return instance;
}
private Singletonlazy(){}
}
在如上懶漢式的代碼中,如果在多線(xiàn)程情況下,就會(huì)出現(xiàn)一些問(wèn)題
在多線(xiàn)程中,線(xiàn)程是搶占式執(zhí)行的。 那么就會(huì)給程序帶來(lái)一些問(wèn)題
由于線(xiàn)程的搶占式執(zhí)行,雖說(shuō)不會(huì)造成空間的浪費(fèi) 但是時(shí)間的消耗確實(shí)客觀存在的。
那么解決這個(gè)問(wèn)題,就進(jìn)行加鎖操作。
public Singletonlazy getInstance(){
synchronized (lock){
if ( instance == null){
instance = new Singletonlazy();
}
}
return instance;
}
這樣加鎖,就是將 if 和 new 打包成一個(gè)原子操作
但是這樣也會(huì)出現(xiàn)問(wèn)題
那么如何解決這個(gè)問(wèn)題呢? 我們?cè)阪i的外層,在添加一個(gè)判斷條件
public Singletonlazy getInstance(){
if (instance == null) {
synchronized (lock){
if ( instance == null){
instance = new Singletonlazy();
}
}
}
return instance;
}
注意: 這里的兩個(gè)if條件雖然內(nèi)容一樣,但是意義卻完全不同
第一個(gè)if是判斷是否要進(jìn)行加鎖操作第二個(gè)if是判斷是否要實(shí)例創(chuàng)建對(duì)象
如上代碼已經(jīng)解決了多線(xiàn)程情況下的線(xiàn)程安全問(wèn)題。 也解決了執(zhí)行效率的問(wèn)題。
但是還存在一個(gè)問(wèn)題 指令重排
4.指令重排
概念:
為了使處理器內(nèi)部的運(yùn)算單元能盡量被充分利用,處理器可能會(huì)對(duì)輸入的代碼進(jìn)行亂序執(zhí)行優(yōu)化,處理器會(huì)在計(jì)算之后將亂序執(zhí)行的結(jié)果重組,并確保這一結(jié)果和順序執(zhí)行結(jié)果是一致的,但是這個(gè)過(guò)程并不保證各個(gè)語(yǔ)句計(jì)算的先后順序和輸入代碼中的順序一致。這就是指令重排序。
通俗的說(shuō),就是在不改變代碼邏輯的條件下,通過(guò)更改指令的執(zhí)行順序,來(lái)達(dá)到優(yōu)化代碼的效果。
舉例:
在這一行代碼中,一個(gè)創(chuàng)建對(duì)象實(shí)例的過(guò)程可以在指令的角度分為三步
申請(qǐng)內(nèi)容空間調(diào)用構(gòu)造方法(對(duì)內(nèi)存空間進(jìn)行初始化)把此時(shí)內(nèi)存空間的地址,賦值給instance引用
在指令重排的優(yōu)化下 可能有 1 --》3 --》 2 1 --》2 --》 3 這樣兩種情況
1是一定在第一步的,因?yàn)槭且诒WC代碼邏輯的前提下,才能進(jìn)行指令重排。
那么如何解決呢? 引入volatile
public static volatile Singletonlazy instance = null;
使用volatile關(guān)鍵字修飾的變量,可以保證其指令執(zhí)行的順序與程序指明的順序一致,不會(huì)發(fā)生順序變換
5.完整代碼
class Singletonlazy{
public static volatile Singletonlazy instance = null;
public static Object lock = new Object();
public Singletonlazy getInstance(){
if (instance == null) {
synchronized (lock){
if ( instance == null){
instance = new Singletonlazy();
}
}
}
return instance;
}
private Singletonlazy(){}
}
以上就是本文所有內(nèi)容,如果對(duì)你有幫助的話(huà),點(diǎn)贊收藏支持一下吧!???
柚子快報(bào)邀請(qǐng)碼778899分享:開(kāi)發(fā)語(yǔ)言 【Java】單例模式
參考閱讀
本文內(nèi)容根據(jù)網(wǎng)絡(luò)資料整理,出于傳遞更多信息之目的,不代表金鑰匙跨境贊同其觀點(diǎn)和立場(chǎng)。
轉(zhuǎn)載請(qǐng)注明,如有侵權(quán),聯(lián)系刪除。