目錄
什么叫做單例模式?
餓漢式和懶漢式的區(qū)別?
餓漢式-方式1(靜態(tài)變量方式)
餓漢式-方式2(靜態(tài)代碼塊方式)
懶漢式-方式1(線程不安全)
懶漢式-方式2(線程安全)
懶漢式-方式3(雙重檢查鎖)
懶漢式-方式4(靜態(tài)內(nèi)部類方式)
什么叫做單例模式?
????????涉及到一個(gè)單一的類,該類負(fù)責(zé)創(chuàng)建自己的對(duì)象,同時(shí)確保只有單個(gè)對(duì)象被創(chuàng)建。這個(gè)類提供 了一種訪問(wèn)其唯一的對(duì)象的方式,可以直接訪問(wèn),不需要實(shí)例化該類的對(duì)象。
餓漢式和懶漢式的區(qū)別?
? ? ? ? 餓漢式:類加載就會(huì)導(dǎo)致該單實(shí)例對(duì)象被創(chuàng)建
? ? ? ? 懶漢式:類加載不會(huì)導(dǎo)致該單實(shí)例對(duì)象被創(chuàng)建,而是首次使用該對(duì)象時(shí)才會(huì)創(chuàng)建
? ? ? ? 導(dǎo)致類加載的情況:new 對(duì)象,創(chuàng)建子類,調(diào)用靜態(tài)屬性
? ? ? ? 類加載是什么意思:就是把你的變量和方法存在內(nèi)存當(dāng)中
? ? ? ? 代碼區(qū)別如下:
? ? ? ? 人話來(lái)說(shuō)就是創(chuàng)建對(duì)象的時(shí)機(jī)不一樣,如果看不懂的話建議去補(bǔ)java基礎(chǔ)靜態(tài)這一塊的知識(shí)
//餓漢式
public class Singleton {
private Singleton(){}
// 提前創(chuàng)建好單列對(duì)象;
private static Singleton instance = new Singleton();
public static Singleton getInstance(){
return instance;
}
}
//測(cè)試代碼:
public class Test {
public static void main (String[] args) {
//因?yàn)檫@里調(diào)用的是靜態(tài)方法,所以導(dǎo)致類加載,就會(huì)執(zhí)行 new Singleton();從而創(chuàng)建對(duì)象
//導(dǎo)致類加載的情況:new 對(duì)象,創(chuàng)建子類,調(diào)用靜態(tài)屬性
Singleton instance = Singleton.getInstance();
Singleton instance1 = Singleton.getInstance();
System.out.println(instance==instance1);
}
}
============================================================================
//餓漢式
public class Singleton {
private Singleton(){}
private static Singleton instance;
public static Singleton getInstance(){
if (instance==null){
//調(diào)用的時(shí)候才創(chuàng)建對(duì)象
//判短對(duì)象為空才創(chuàng)建對(duì)象
instance=new Singleton();
}
return instance;
}
}
public class Test {
public static void main (String[] args) {
//調(diào)用方法的時(shí)候才創(chuàng)建對(duì)象
Singleton instance = Singleton.getInstance();
Singleton instance1 = Singleton.getInstance();
System.out.println(instance==instance1);
}
}
餓漢式-方式1(靜態(tài)變量方式)
?
/**
* 餓漢式
* 靜態(tài)變量創(chuàng)建類的對(duì)象
*/
public class Singleton {
//私有構(gòu)造方法
private Singleton() {}
//在成員位置創(chuàng)建該類的對(duì)象
private static Singleton instance = new Singleton();
//對(duì)外提供靜態(tài)方法獲取該對(duì)象
public static Singleton getInstance() {
return instance;
}
}
缺點(diǎn):
該方式在成員位置聲明Singleton類型的靜態(tài)變量,并創(chuàng)建Singleton類的對(duì)象instance。 instance對(duì)象是隨著類的加載而創(chuàng)建的。如果該對(duì)象足夠大的話,而一直沒(méi)有使用就會(huì)造成內(nèi)存 的浪費(fèi)。
餓漢式-方式2(靜態(tài)代碼塊方式)
?
/**
* 惡漢式
* 在靜態(tài)代碼塊中創(chuàng)建該類對(duì)象
*/
public class Singleton {
//私有構(gòu)造方法
private Singleton() {}
//在成員位置創(chuàng)建該類的對(duì)象
private static Singleton instance;
static {
instance = new Singleton();
}
//對(duì)外提供靜態(tài)方法獲取該對(duì)象
public static Singleton getInstance() {
return instance;
}
}
缺點(diǎn):
該方式在成員位置聲明Singleton類型的靜態(tài)變量,而對(duì)象的創(chuàng)建是在靜態(tài)代碼塊中,也是對(duì)著 類的加載而創(chuàng)建。所以和餓漢式的方式1基本上一樣,當(dāng)然該方式也存在內(nèi)存浪費(fèi)問(wèn)題。
懶漢式-方式1(線程不安全)
/**
* 懶漢式
* 線程不安全
*/
public class Singleton {
//私有構(gòu)造方法
private Singleton() {}
//在成員位置創(chuàng)建該類的對(duì)象
private static Singleton instance;
//對(duì)外提供靜態(tài)方法獲取該對(duì)象
public static Singleton getInstance() {
if(instance == null) {
instance = new Singleton();
}
return instance;
}
}
缺點(diǎn):
從上面代碼我們可以看出該方式在成員位置聲明Singleton類型的靜態(tài)變量,并沒(méi)有進(jìn)行對(duì)象的 賦值操作,那么什么時(shí)候賦值的呢?當(dāng)調(diào)用getInstance()方法獲取Singleton類的對(duì)象的時(shí) 候才創(chuàng)建Singleton類的對(duì)象,這樣就實(shí)現(xiàn)了懶加載的效果。但是,如果是多線程環(huán)境,會(huì)出現(xiàn) 線程安全問(wèn)題。
懶漢式-方式2(線程安全)
?
/**
* 懶漢式
* 線程安全
*/
public class Singleton {
//私有構(gòu)造方法
private Singleton() {}
//在成員位置創(chuàng)建該類的對(duì)象
private static Singleton instance;
//對(duì)外提供靜態(tài)方法獲取該對(duì)象
public static synchronized Singleton getInstance() {
if(instance == null) {
instance = new Singleton();
}
return instance;
}
}
缺點(diǎn):
該方式也實(shí)現(xiàn)了懶加載效果,同時(shí)又解決了線程安全問(wèn)題。但是在getInstance()方法上添加了 synchronized關(guān)鍵字,導(dǎo)致該方法的執(zhí)行效果特別低。從上面代碼我們可以看出,其實(shí)就是在 初始化instance的時(shí)候才會(huì)出現(xiàn)線程安全問(wèn)題,一旦初始化完成就不存在了。
就是每個(gè)現(xiàn)場(chǎng)都會(huì)拿到鎖,導(dǎo)致效率降低,應(yīng)該是當(dāng)沒(méi)有獲取對(duì)象的誰(shuí)時(shí)候拿到鎖。
?
懶漢式-方式3(雙重檢查鎖)
?
public class Singleton {
private Singleton(){}
//聲明一個(gè)Singleton類型的變量
private static Singleton instance;
public static Singleton getInstance(){
if (instance==null){
//為空的時(shí)候才會(huì)拿到鎖
synchronized (Singleton.class){
if (instance==null){
instance=new Singleton();
}
}
}
return instance;
}
}
雙重檢查鎖模式是一種非常好的單例實(shí)現(xiàn)模式,解決了單例、性能、線程安全問(wèn)題,上面的雙重檢 測(cè)鎖模式看上去完美無(wú)缺,其實(shí)是存在問(wèn)題,在多線程的情況下,可能會(huì)出現(xiàn)空指針問(wèn)題,出現(xiàn)問(wèn) 題的原因是JVM在實(shí)例化對(duì)象的時(shí)候會(huì)進(jìn)行優(yōu)化和指令重排序操作。 要解決雙重檢查鎖模式帶來(lái)空指針異常的問(wèn)題,只需要使用 volatile 關(guān)鍵字, volatile 關(guān) 鍵字可以保證可見性和有序性。
?文章來(lái)源:http://www.zghlxwxcb.cn/news/detail-653427.html
懶漢式-方式4(靜態(tài)內(nèi)部類方式)
?
public class Singleton {
//私有構(gòu)造方法
private Singleton() {}
private static class SingletonHolder {
private static final Singleton INSTANCE = new Singleton();
}
//對(duì)外提供靜態(tài)方法獲取該對(duì)象
public static Singleton getInstance() {
return SingletonHolder.INSTANCE;
}
}
?第一次加載Singleton類時(shí)不會(huì)去初始化INSTANCE,只有第一次調(diào)用getInstance,虛擬機(jī)加 載SingletonHolder 并初始化INSTANCE,這樣不僅能確保線程安全,也能保證 Singleton 類的唯一性。 小結(jié): 靜態(tài)內(nèi)部類單例模式是一種優(yōu)秀的單例模式,是開源項(xiàng)目中比較常用的一種單例模式。在沒(méi)有加任 何鎖的情況下,保證了多線程下的安全,并且沒(méi)有任何性能影響和空間的浪費(fèi)。文章來(lái)源地址http://www.zghlxwxcb.cn/news/detail-653427.html
到了這里,關(guān)于單例設(shè)計(jì)模式精講(餓漢式和懶漢式實(shí)現(xiàn)的重要方法)的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!