概念
????????保證指定的類只有一個實例,不能創(chuàng)建出其他的實例
實現(xiàn)方式
? ? ? ? 1.餓漢模式
? ? ? ? ? ? ? ? 1.1 代碼展示
package 設(shè)計模式;
/**
* Created with IntelliJ IDEA.
* Description:
* User: wuyulin
* Date: 2023-07-28
* Time: 11:28
*/
//單例模式(餓漢模式)
//保證Singleton類只有一個實例
//Singleton類中instance對象的創(chuàng)建時機:在Singleton類被jvm加載的時候創(chuàng)建,Singleton類會在第一次使用的時候被加載,不一定是程序一啟動的時候
class Singleton{
//帶有static的是類屬性,由于每個類的類對象是單例的,所以類對象的屬性(static)也是單例的
private static Singleton instance=new Singleton();
public static Singleton getSingleton(){
return instance;
} //當多個線程調(diào)用getSingleton方法相當于多個線程讀取同一個變量,這是線程安全的
//由于要規(guī)定在類的外部不能實例化Singleton類型的對象,所以要把構(gòu)造函數(shù)改為私有的,這樣就在類外部就不能實例化Singleton類的對象了
private Singleton(){};
}
public class Deom1 {
public static void main(String[] args) {
Singleton s1=Singleton.getSingleton();
Singleton s2=Singleton.getSingleton();
//Singleton s3=new Singleton();
System.out.println(s1==s2);
//System.out.println(s1==s3);
}
}
? ? ? ? ? ? ? ? 1.2 Singleton類中instance對象的創(chuàng)建時機
????????????????Singleton類中instance對象的創(chuàng)建時機:在Singleton類被jvm加載的時候創(chuàng)建,Singleton類會在第一次使用的時候被加載,不一定是程序一啟動的時候
? ? ? ? ? ? ? ? 1.3 控制Singleton類的實例只有一個的核心步驟
? ? ? ? ? ? ? ? ? ? ? ? 1.3.1 在類屬性(static)中進行創(chuàng)建,帶有static的是類屬性,由于每個類的類對象是單例的,所以類對象的屬性(static)也是單例的
? ? ? ? ? ? ? ? ? ? ? ? 1.3.2 提供一個獲取這個對象的接口,方便在類外調(diào)用這個對象
? ? ? ? ? ? ? ? ? ? ? ? 1.3.3 由于規(guī)定在類的外部不能實例化Singleton類型的對象,所以要把構(gòu)造函數(shù)改為私有的,這樣就在類外部就不能實例化Singleton類的對象了
? ? ? ? ? ? ? ? 1.4線程安全問題
????????????????餓漢模式實現(xiàn)單例模式是沒有線程安全問題的,因為多個線程調(diào)用getSingleton()方法,相當于多個線程讀取instance引用的值,沒有涉及到多個線程進行修改,所以沒有線程安全問題
? ? ? ? 2.懶漢模式
? ? ? ? ? ? ? ? 2.1代碼展示
package 設(shè)計模式;
/**
* Created with IntelliJ IDEA.
* Description:
* User: wuyulin
* Date: 2023-07-28
* Time: 12:05
*/
//單例線程(懶漢模式)
//SingletonLazy類中instance對象創(chuàng)建的時機:在第一次調(diào)用getInstance()方法時創(chuàng)建
class SingletonLazy{
private static volatile SingletonLazy instance=null; //加上volatile避免內(nèi)存可見性問題
public static SingletonLazy getInstance(){
if(instance==null){ //第一個條件判斷是否需要加鎖
synchronized(SingletonLazy.class){ //第二個條件用于判斷是否要創(chuàng)建對象
if(instance==null){
instance=new SingletonLazy();
}
}
}
return instance;
}
private SingletonLazy(){};
}
public class Demo2 {
public static void main(String[] args) {
SingletonLazy s1=SingletonLazy.getInstance();
SingletonLazy s2=SingletonLazy.getInstance();
System.out.println(s1==s2);
//SingletonLazy s3=new SingletonLazy();
}
}
? ? ? ? ? ? ? ? 2.2SingletonLazy類中instance對象創(chuàng)建的時機
????????????????????????在第一次調(diào)用getInstance()方法時創(chuàng)建
? ? ? ? ? ? ? ? 2.3控制SingletonLazy類的實例只有一個的核心步驟
? ? ? ? ? ? ? ? ? ? ? ? 2.3.1在類屬性(static)中進行創(chuàng)建聲明,帶有static的是類屬性,由于每個類的類對象是單例的,所以類對象的屬性(static)也是單例的
? ? ? ? ? ? ? ? ? ? ? ? 2.3.2 提供一個實例化這個對象并返回這個對象的接口
? ? ? ? ? ? ? ? ? ? ? ? 2.3.3 由于規(guī)定在類的外部不能實例化Singleton類型的對象,所以要把構(gòu)造函數(shù)改為私有的,這樣就在類外部就不能實例化Singleton類的對象了
? ? ? ? ? ? ? ? 2.4 線程安全問題
????????????????????????懶漢模式存在線程安全問題
????????????????????????當多個線程判斷instance=null,可能多個線程都會判斷為null值,導(dǎo)致創(chuàng)建多個對象,所以要對getInstance()方法中的代碼進行加鎖,將判斷和創(chuàng)建對象兩個操作變成一個原子性的操作
????????????????????????但實際上是需要一直加鎖的嗎?不是的,只有我們準備實例化instance對象的時候會出現(xiàn)線程安全問題,當創(chuàng)建成功后,instance!=null,此時多個線程都是獲得instance引用的值,不存在線程安全問題,也就不需要加鎖了,所以要判斷一下是否需要加鎖,當instance為null表示當前第一次準備創(chuàng)建該對象,此時加鎖控制只有第一個線程創(chuàng)建對象,其余線程返回instance的值,instance不為null說明instance對象已經(jīng)創(chuàng)建成功,多個線程都只是讀取instance的值,不存在線程安全問題,所以不用加鎖
?????????????????????加了鎖以后該程序其實還有內(nèi)存可見性問題,因為在第一次調(diào)用getInstance()方法創(chuàng)建對象后,第二次去讀取instance的值,你不一定能讀到最新的instance的值,原因請看線程安全問題(內(nèi)存可見性),所以要在instance變量聲明的時候加上volatile(易變的),解決內(nèi)存可見性問題
? ? ? ? ? ? ? ? ? ? ? 使用volatile不僅僅是為了預(yù)防出現(xiàn)內(nèi)存可見性問題,還要解決指令重排序問題,指令重排序問題請看線程安全問題(指令重排序)文章來源:http://www.zghlxwxcb.cn/news/detail-613489.html
????????????????????????文章來源地址http://www.zghlxwxcb.cn/news/detail-613489.html
到了這里,關(guān)于設(shè)計模式(單例模式)的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!