国产一级a片免费看高清,亚洲熟女中文字幕在线视频,黄三级高清在线播放,免费黄色视频在线看

打開APP
userphoto
未登錄

開通VIP,暢享免費(fèi)電子書等14項(xiàng)超值服

開通VIP
java單例模式二
 

本人參考了:Balan的文章 Java Singleton 實(shí)用教程(附源碼)

原文地址:http://balan.javaeye.com/blog/164873

一、定義

單例模式(Singleton pattern):確保一個(gè)類只有一個(gè)實(shí)例,并提供一個(gè)全局的訪問點(diǎn)。

這個(gè)定義包含兩層意思:

第一:我們把某個(gè)類設(shè)計(jì)成自己管理的一個(gè)單獨(dú)實(shí)例,同時(shí)也要避免其他類再自行產(chǎn)生實(shí)例。要想取得單個(gè)實(shí)例,通過單例類是唯一的途徑。

第二:我們必需提供對這個(gè)實(shí)例的全局訪問點(diǎn):當(dāng)你需要實(shí)例時(shí),向類查詢,它會給你返回單個(gè)實(shí)例。

注意:單例模式確保一個(gè)類只有一個(gè)實(shí)例,是指在特定系統(tǒng)范圍內(nèi)只能有一個(gè)實(shí)例。有時(shí)在某些情況下,使用Singleton并不能達(dá)到Singleton的目的,如有多個(gè)Singleton對象同時(shí)被不同的類裝入器裝載;在EJB這樣的分布式系統(tǒng)中使用也要注意這種情況,因?yàn)镋JB是跨服務(wù)器,跨JVM的。

1。某個(gè)框架容器內(nèi):如Spring IOC容器,可以通過配置保證實(shí)例在容器內(nèi)的唯一性。

2。再如單一JVM中、單一類加載器加載類的情況可以保證實(shí)例的唯一性。

如果在兩個(gè)類加載器或JVM中,可能他們有機(jī)會各自創(chuàng)建自己的單個(gè)實(shí)例,因?yàn)槊總€(gè)類加載器都定義了一個(gè)命名空間,如果有兩個(gè)以上的類加載器,不同的類加載器可能會加載同一個(gè)類,從整個(gè)程序來看,同一個(gè)類會被加載多次。如果這樣的事情發(fā)生在單例上,就會產(chǎn)后多個(gè)Singleton并存的怪異現(xiàn)象。所以如果你的程序有多個(gè)類加載,同時(shí)你又使用了單例模式,請一定要小心。有一個(gè)解決辦法是,自行給單例類指定類加載器(指定同一個(gè)類加載器)。

二、用處

有一些對象其實(shí)我們完全只需要一個(gè)即可,如:線程池(threadpool)、緩存(cache)、注冊表(registry)的對象、設(shè)備的驅(qū)動(dòng)程序的對象等等。事實(shí)上,這些類的對象只能有一個(gè)實(shí)例,如果制造出多個(gè)實(shí)例,就會導(dǎo)致許多問題的產(chǎn)生,例如:程序的行為異常、資源的過量使用、產(chǎn)生不一致的結(jié)果等等。Java Singleton模式就為我們提供了這樣實(shí)現(xiàn)的可能。使用Singleton的好處還在于可以節(jié)省內(nèi)存,因?yàn)樗拗屏藢?shí)例的個(gè)數(shù),有利于Java垃圾回收(garbage collection)。我們常??吹焦S模式中類裝入器(class loader)中也用Singleton模式實(shí)現(xiàn)的,因?yàn)楸谎b入的類實(shí)際也屬于資源。

三、Java Singleton模式常見的幾種形式

一)。使用立即創(chuàng)建實(shí)例,而不用延遲實(shí)例化的做法

1。使用全局變量

Java代碼
  1. //Singleton with final field   
  2. public class Singleton {   
  3.     public static final Singleton uniqueInstance = new Singleton();   
  4.     private Singleton(){   
  5.     }   
  6.     //...Remainder omitted   
  7. }  

 在這種方法中,公有靜態(tài)成員是一個(gè)final域(保證了總是包含相同的對象引用)。私有構(gòu)造函數(shù)僅被調(diào)用一次,用來實(shí)例化公有的靜態(tài)final域 Singleton.uniqueInstace。由于缺少公有的或者受保護(hù)的構(gòu)造函數(shù),所有保證了Singleton的全局唯一性:一旦 Singleton類被實(shí)例化之后,只有一個(gè)Singleton實(shí)例存在——不多也不少。使用此Singleton類的程序員的任何行為都不能改變這一點(diǎn)。

2。使用公有的靜態(tài)工廠方法

Java代碼
  1. //Singleton with static factory   
  2. public class Singleton {   
  3.     private static Singleton uniqueInstance = new Singleton();   
  4.     private Singleton(){   
  5.     }   
  6.     public static Singleton getInSingleton(){   
  7.         return uniqueInstance;   
  8.     }   
  9.     //...Remainder omitted   
  10. }  

 第二種方法提供了一個(gè)公有的靜態(tài)工廠方法,而不是公有的靜態(tài)final域。利用這個(gè)做法,我們依賴JVM在加載這個(gè)類時(shí)馬上創(chuàng)建此類唯一的一個(gè)實(shí)例。JVM保證任何線程訪問uniqueInstance靜態(tài)變量之前,一定先創(chuàng)建此實(shí)例。

二)。使用延遲實(shí)例化的做法(使用公有的靜態(tài)工廠方法)

1。非線程安全的

Java代碼
  1. public class Singleton {   
  2.     private static Singleton uniqueInstance ;   
  3.     private Singleton(){   
  4.     }   
  5.     public static Singleton getInSingleton(){   
  6.         if(uniqueInstance == null){   
  7.             uniqueInstance = new Singleton();   
  8.         }   
  9.         return uniqueInstance;   
  10.     }   
  11.     //...Remainder omitted   
  12. }  

 先利用一個(gè)靜態(tài)變量uniqueInstance來記錄Singleton類的唯一實(shí)例,當(dāng)我們要使用它的實(shí)例時(shí),如果它不存在,就利用私有的構(gòu)造器產(chǎn)生一個(gè)Singleton類的實(shí)例并把它賦值到uniqueInstance靜態(tài)變量中。而如果我們不需要使用這個(gè)實(shí)例,它就永遠(yuǎn)不會產(chǎn)生。這就是"延遲實(shí)例化(lazy instantiaze)"。但上面這段程序在多線程環(huán)境中是不能保證單個(gè)實(shí)例的。分析如下:

時(shí)間點(diǎn) 線程1 線程2 uniqueInstance的值
1 線程1,2同時(shí)訪問Singleton.getInstance()方法
2 進(jìn)入Singleton.getInstance()方法  null
3 進(jìn)入Singleton.getInstance()方法  null
4 執(zhí)行if(uniqueInstance == null)判斷  null
5 執(zhí)行if(uniqueInstance == null)判斷  null
6 執(zhí)行uniqueInstance = new Singleton() Singleton1
7 執(zhí)行uniqueInstance = new Singleton() Singleton2
8 執(zhí)行return uniqueInstance; Singleton1
9 執(zhí)行return uniqueInstance; Singleton2

如上分析所示,它已產(chǎn)生了兩個(gè)Singleton實(shí)例。

2。多線程安全的

Java代碼
  1. public class Singleton {   
  2.     private static Singleton uniqueInstance ;   
  3.     private Singleton(){   
  4.     }   
  5.     public synchronized static Singleton getInSingleton(){   
  6.         if(uniqueInstance == null){   
  7.             uniqueInstance = new Singleton();   
  8.         }   
  9.         return uniqueInstance;   
  10.     }   
  11.     //...Remainder omitted   
  12. }  

 通過給getInstance()方法增加synchronized關(guān)鍵字,也就是給getInstance()方法線程加鎖,迫使每次只能有一個(gè)線程在進(jìn)入這個(gè)方法,這樣就可以解決上面多線程產(chǎn)生的災(zāi)難了。但加鎖的同步方法可能造成程序執(zhí)行效率大幅度下降,如果你的程序?qū)π阅艿囊蠛芨?,同時(shí)你的getInstance()方法調(diào)用的很頻繁,這時(shí)可能這種設(shè)計(jì)也不符合程序要求了。其實(shí)這種加鎖同步的方法用在這確實(shí)有一定的問題存在,因?yàn)閷?Singleton類來說,只有在第一次執(zhí)行g(shù)etInstance()方法時(shí),才真正的需要對方法進(jìn)行加鎖同步,因?yàn)橐坏┑谝淮卧O(shè)置好 uniqueInstance變量后,就不再需要同步這個(gè)方法了。之后每次調(diào)用這個(gè)方法,同步反而成了一種累贅。

3。 用"雙重檢查加鎖",在getInstance()方法中減少使用同步:

Java代碼
  1. public class Singleton {   
  2.     // volatile關(guān)鍵字確保當(dāng)uniqueInstance變量被初始化成Singleton實(shí)例時(shí),多個(gè)線程正確地處理uniqueInstance變量   
  3.     private volatile static Singleton uniqueInstance;   
  4.     private Singleton() {   
  5.     }   
  6.   
  7.     public static Singleton getInSingleton() {   
  8.         if (uniqueInstance == null) {// 檢查實(shí)例,如是不存在就進(jìn)行同步代碼區(qū)   
  9.             synchronized (Singleton.class) {// 對其進(jìn)行鎖,防止兩個(gè)線程同時(shí)進(jìn)入同步代碼區(qū)   
  10.                 if (uniqueInstance == null) {// 雙重檢查,非常重要,如果兩個(gè)同時(shí)訪問的線程,當(dāng)?shù)谝痪€程訪問完同步代碼區(qū)后,生成一個(gè)實(shí)例;當(dāng)?shù)诙€(gè)已進(jìn)入getInstance方法等待的線程進(jìn)入同步代碼區(qū)時(shí),也會產(chǎn)生一個(gè)新的實(shí)例   
  11.                     uniqueInstance = new Singleton();   
  12.                 }   
  13.             }   
  14.         }   
  15.         return uniqueInstance;   
  16.     }   
  17.     // ...Remainder omitted   
  18. }  

對于雙重檢查加鎖(Double-Checked Locking)有一篇文章解釋的很深入:http://www.cs.umd.edu/~pugh/java/memoryModel/DoubleCheckedLocking.html

三。Sington類的序列化

為了使Singleton類變成可序列化的(serializable),僅僅實(shí)現(xiàn)Serializable接口是不夠的。為了維護(hù) Singleton的單例性,你必須給Singleton類提供一個(gè)readResolve方法,否則的話,一個(gè)序列化的實(shí)例,每次反序列化的時(shí)候都會產(chǎn)生一個(gè)新的實(shí)例。Singleton 也不會例外。

如下所示:

Java代碼
  1. import java.io.FileInputStream;   
  2. import java.io.FileOutputStream;   
  3. import java.io.ObjectInputStream;   
  4. import java.io.ObjectOutputStream;   
  5. import java.io.ObjectStreamException;   
  6. import java.io.Serializable;   
  7.   
  8. //Singleton with final field   
  9. public class Singleton implements Serializable{   
  10.   
  11.     private static final long serialVersionUID = 5765648836796281035L;   
  12.     public static final Singleton uniqueInstance = new Singleton();   
  13.     private Singleton(){   
  14.     }   
  15.     //...Remainder omitted   
  16.     public static void main(String[] args) throws Exception{   
  17.         //序列化   
  18.          ObjectOutputStream objectOutputStream = new ObjectOutputStream(new FileOutputStream("D:\\Singleton.obj"));   
  19.          Singleton singleton = Singleton.uniqueInstance;            
  20.          objectOutputStream.writeObject(singleton);   
  21.          objectOutputStream.close();   
  22.          //反序列化   
  23.          ObjectInputStream objectInputStream = new ObjectInputStream(new FileInputStream("D:\\Singleton.obj"));   
  24.          Singleton singleton2 = (Singleton)objectInputStream.readObject();   
  25.          objectInputStream.close();   
  26.          //比較是否原來的實(shí)例   
  27.          System.out.println(singleton==singleton2);   
  28.    }    
  29. }  

 輸出結(jié)果為:false

解決方法是為Singleton類增加readResolve()方法:

Java代碼
  1. //readResolve 方法維持了Singleton的單例屬性   
  2.     private Object readResolve() throws ObjectStreamException{   
  3.         return uniqueInstance;   
  4.     }  

 再進(jìn)行測試:輸出結(jié)果為true

 

反序列化之后新創(chuàng)建的對象會先調(diào)用此方法,該方法返回的對象引用被返回,取代了新創(chuàng)建的對象。本質(zhì)上,該方法忽略了新建對象,仍然返回類初始化時(shí)創(chuàng)建的那個(gè)實(shí)例。
 
 
本站僅提供存儲服務(wù),所有內(nèi)容均由用戶發(fā)布,如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請點(diǎn)擊舉報(bào)。
打開APP,閱讀全文并永久保存 查看更多類似文章
猜你喜歡
類似文章
5.2.3 單例模式示例代碼
博客園 - Allen Young - 當(dāng)Singleton遇到multi-threading
設(shè)計(jì)模式讀書筆記-----單例模式
枚舉實(shí)現(xiàn)單例模式
深入靈魂的考驗(yàn),每行注釋都是靈魂的單例模式,源碼+實(shí)例降臨
C# 用Singleton類構(gòu)建多線程單例模式
更多類似文章 >>
生活服務(wù)
分享 收藏 導(dǎo)長圖 關(guān)注 下載文章
綁定賬號成功
后續(xù)可登錄賬號暢享VIP特權(quán)!
如果VIP功能使用有故障,
可點(diǎn)擊這里聯(lián)系客服!

聯(lián)系客服