單例模式有幾種?如何優化?
在某些系統中,為了節省內存資源和保證數據內容的一致性,對于某些類只能創建一個實例,這種模式稱為singleton模式。
單體模式的定義和特征
Singleton模式的定義:指一個類只有一個實例,并且該類可以自己創建這個實例的模式。比如在Windows中只能打開一個任務管理器,可以避免打開多個任務管理器窗口造成的內存資源浪費,或者每個窗口顯示內容不一致。
在計算機系統中,還有Windows的回收站,操作系統中的文件系統,多線程中的線程池,顯卡的驅動對象,打印機的后臺處理服務,應用程序的日志對象,數據庫的連接池,網站的計數器,Web應用程序的配置對象,應用程序中的對話框,系統中的緩存,這些往往被設計成單一的案例。
Singleton模式在現實生活中也有廣泛應用,比如公司CEO、部門經理等。J2EE標準中的ServletContext和ServletContextConfig,Spring框架應用中的ApplicationContext和數據庫中的連接池也是singleton模式。
單例模式有三個特征:
單例類只有一個實例對象;singleton對象必須由singleton類本身創建;singleton類為訪問singleton提供了一個全局訪問點。單例模式的優點和缺點。
單例模式的優勢:
Singleton模式可以保證內存中只有一個實例,減少了內存開銷。可以避免多次占用資源。Singleton模式設置了全局訪問點,可以優化和共享對資源的訪問。單一模式和。;的缺點:
Singleton模式一般沒有接口,所以很難擴展。如果要擴展,除了修改原代碼,沒有第二條路,這違背了開放封閉原則。在并發測試中,單件模式不利于代碼調試。在調試期間,如果singleton中的代碼沒有完成,就不能模擬新的對象。單一模式和。;的功能代碼通常寫在一個類中。如果功能設計不合理,很容易違反單一責任原則。Singleton模式看起來很簡單,實現起來也很簡單。單體模式是面試中的一個高頻面試問題。希望大家好好學習,掌握獨生子女模式,提升核心競爭力,給面試加分,順利拿到Offer。
單一模式和。;的應用場景
對于Java,singleton模式可以保證在一個JVM中只有一個實例。單一模式和。;的應用場景主要包括以下幾個方面。
對于一些需要經常創建的類,使用單例可以減輕系統的內存壓力,減少GC。當一個類只需要生成一個對象時,比如一個類的班長,每個人s身份證號等。有些類在創建實例時會占用更多的資源,或者實例化需要很長時間,并且經常被使用。當一個類需要頻繁實例化,并且創建的對象被頻繁銷毀時,比如多線程線程池、網絡連接池等。頻繁訪問數據庫或文件的對象。對于一些控制硬件層面的操作,或者從系統角度看應該是單個控制邏輯的操作,如果有多個實例,系統就完全亂套了。當需要共享對象時。因為在單例模式中只能創建一個對象,所以共享這個對象可以節省內存并加快對象訪問。如Web中的配置對象、數據庫的連接池等。singleton模式的結構與實現
單一模式是最簡單的設計模式之一。通常,普通類的構造函數是公共的,外部類可以通過"新構造函數()"。但是,如果將類的構造函數設置為private,則外部類無法調用該構造函數,因此無法生成多個實例。此時,類本身必須定義一個靜態私有實例,并提供一個靜態公共函數來創建或獲取靜態私有實例。
讓分析了它的基本結構和實現方法。
1.單例模式的結構
單一模式和。;的主要角色如下。
Singleton類:包含一個實例并且可以自己創建這個實例的類。訪問類:使用單例的類。其結構如圖1所示。
圖1單例模式的結構圖。
2.單例模式的實現
單例模式通常有兩種實現形式。
第一種:懶惰的單一案例
這種模式的特點是類加載時不生成singleton,只有第一次調用getlnstance方法時才創建。代碼如下:
公共類LazySingleton{
privatestaticvolatilelazysingleton實例null//確保實例在所有線程中同步。
列兵LazySingleton(){
}//private防止類被外部實例化。
公共靜態同步LazySingletongetInstance(){
//在//getInstance方法之前同步
if(實例為空){
實例newLazySingleton()
}
返回實例
}
}
注意:如果你正在寫一個多線程程序,不要不要刪除前面代碼中的關鍵字volatile和synchronized,否則會有線程不安全的問題。如果你不t刪除這兩個關鍵字,可以保證線程安全,但是每次訪問都要同步,會影響性能,消耗更多資源。這就是懶單胞的缺點。第二種:餓漢式單例
這種模式的特點是,一旦加載了類,就會創建一個singleton,這確保了在調用getInstance方法之前該singleton已經存在。
公共類饑餓Singleton{
私有靜態最終HungrySingleton實例newHungrySingleton()
二等兵HungrySingleton(){
}
公共靜態HungrySingletongetInstance(){
返回實例
}
}
餓了么中文singleton在創建類的同時創建了一個靜態對象供系統使用,以后也不會更改,所以是線程安全的,可以直接用于多線程,沒有問題。
單例模式的應用實例
【例1】使用lazysingleton模式模擬生成美國當前總統對象。
分析:每屆美國只有一位總統,所以這個例子適合用singleton模式來實現。圖2是lazysingleton實現的結構圖。
圖2美國總統發電機結構圖
程序代碼如下:
公共類SingletonLazy{
公共靜態voidmain(String[]args){
zt1總裁()
()//輸出總統的名字。
zt2總統()
()//輸出總統的名字。
if(zt1zt2){
他們是同一個人!)
}否則{
(他們不是同一個人!)
}
}
}
班長{
私有靜態易變總統實例null//確保實例在所有線程中同步。
//private防止類被外部實例化。
私人總裁(){
(產生一個總統!)
}
公共靜態同步總統getInstance(){
//向getInstance方法添加同步。
if(實例為空){
實例新總裁()
}否則{
已經有總統了,新總統無法產生!)
}
返回實例
}
publicvoidgetName(){
(我是美國總統:特朗普。)}
}
程序運行結果如下:
產生一個總統!
我是美國總統:特朗普。
已經有總統了,新總統無法產生!
我是美國總統:特朗普。
他們是同一個人!
【例2】用餓漢風格的單體模式模擬生成豬八戒對象。
分析:和前面的例子類似,只有一個豬八戒,所以這個例子也適合用singleton模式實現,所以使用了框架形式的Jframe組件。這里的豬八戒類是一個singleton類,可以定義為panelJPanel的子類,包含了保存豬八戒圖片的標簽,客戶端表單可以獲取豬八戒對象并顯示。圖3是餓了么漢單例實現的結構圖。
圖3豬八戒發電機結構圖
程序代碼如下:
導入*
導入javax.swing.*
公共類單身者{
公共靜態voidmain(String[]args){
Jframejf新Jframe(饑餓單例模式測試)
(新網格布局(1,2))
容器內容窗格()
八戒obj1()
(obj1)
八戒obj2()
(obj2)
if(obj1obj2){
他們是同一個人!)
}否則{
(他們不是同一個人!)
}
()
(正確)
(Jframe。出口_開_關)
}
}
Bajie類擴展JPanel{
私有靜態Bajie實例newBajie()
大兵八戒(){
JLabell1新JLabel(新圖像圖標())
(l1)
}
公共靜態BajiegetInstance(){
返回實例
}
}
程序的運行結果如圖4所示。
圖4豬八戒發電機運行結果
單例模式的擴展
Singleton模式可以擴展為有限的multi-TCM模式,可以生成有限數量的實例并保存在ArrayList中,客戶需要時可以隨機獲取。其結構圖如圖5所示。
圖5有限多實例模式的結構圖
Spring如何解決循環依賴的問題?
你的問題太大了,很難解釋清楚。簡單來說,Spring執行InstantiateBean中的構造器方法來構造一個實例。如果它是單例的,它將將其放入singletonBeanFactory的緩存中,然后執行populateBean方法來設置屬性。循環依賴的問題通過singletonBeanFactory的緩存來解決。推薦你看看這個鏈接。作者講得非常仔細清晰。