国产片侵犯亲女视频播放_亚洲精品二区_在线免费国产视频_欧美精品一区二区三区在线_少妇久久久_在线观看av不卡

服務器之家:專注于服務器技術及軟件下載分享
分類導航

PHP教程|ASP.NET教程|Java教程|ASP教程|編程技術|正則表達式|C/C++|IOS|C#|Swift|Android|VB|R語言|JavaScript|易語言|vb.net|

服務器之家 - 編程語言 - Java教程 - 詳解Java中如何正確書寫單例模式

詳解Java中如何正確書寫單例模式

2020-07-22 14:46又是火星人 Java教程

一般單例都是五種寫法:懶漢,餓漢,雙重校驗鎖,靜態內部類和枚舉。本文整理了幾種常見的單例寫法,下面跟著小編一起來看下吧

單例模式算是設計模式中最容易理解,也是最容易手寫代碼的模式,但是其中涉及的知識點卻一點也不少,所以經常作為面試題來考。一般單例都是五種寫法:懶漢,餓漢,雙重校驗鎖,靜態內部類和枚舉。為了記錄學習過程的過程,這里整理了幾種常見的單例寫法,

詳解Java中如何正確書寫單例模式

青銅5:(Lazy-loaded,但線程不安全)

當被問到要實現一個單例模式時,很多人的第一反應是寫出如下的代碼,包括教科書上也是這樣教我們的。

?
1
2
3
4
5
6
7
8
9
10
public class Singleton {
 private static Singleton instance;
 private Singleton(){}
 public static Singleton getInstance() {
 if (instance == null) {
 instance = new Singleton();
 }
 return instance;
 }
}

這段代碼簡單明了,而且使用了延遲加載模式,但是線程不安全。多線程環境下調用 getInstance() 方法,可能會發生多個線程進入if語句的程序代碼塊。

懶漢式:synchronized(Lazy-loaded,線程安全,但不高效)

為了解決上面的問題,最簡單的方法是將整個 getInstance() 方法設為同步(synchronized)。

?
1
2
3
4
5
6
7
8
9
10
public class Singleton {
 private static Singleton instance;
 private Singleton() {}
 public static synchronized Singleton getInstance() {
 if (instance == null) {
 instance = new Singleton();
 }
 return instance;
 }
}

雖然做到了線程安全、延遲加載,但是它并不高效。因為在任何時候只能有一個線程調用 getInstance() 方法。但是synchronized操作只需要在第一次調用時才被需要,即第一次創建單例實例對象時。這種模式導致即使在單例創建完成后,每次依然只有一個線程可以訪問getInstance()方法,會導致潛在的性能問題。這就引出了雙重檢驗鎖。

餓漢式:static final field(非Lazy-loaded)

這種方法非常簡單,因為單例的實例被聲明成 static final,在第一次加載類到內存中時就會初始化,所以創建實例對象是線程安全的(由JVM實現保證)。

?
1
2
3
4
5
6
7
8
public class Singleton{
 //類加載時就初始化
 private static final Singleton instance = new Singleton();
 private Singleton(){}
 public static Singleton getInstance(){  // Singleton with static factory
 return instance;
 }
}

它不是一種懶加載模式,instance會在加載類后一開始就被初始化,即使客戶端沒有調用 getInstance()方法。這會導致一些使用限制:譬如 Singleton 實例的創建是依賴參數或者配置文件的,在 getInstance() 之前必須調用某個方法設置參數給它,那樣這種單例寫法就無法使用了。類似的方法還有:

?
1
2
3
4
5
public class Singleton{
 public static final Singleton instance = new Singleton(); // Singleton with public final field
 private Singleton(){}
}
// <Effective Java>第14頁講訴了兩者的差異

雙重檢驗鎖 + volatile(Lazyload,線程安全,但晦澀)

雙重檢驗鎖模式(double checked locking pattern),是一種使用同步塊加鎖的方法。程序員稱其為雙重檢查鎖,因為會有兩次檢查 instance == null,一次是在同步塊外,一次是在同步塊內。為什么在同步塊內還要再檢驗一次?因為可能會有多個線程一起進入同步塊外的 if,如果在同步塊內不進行二次檢驗的話就會生成多個實例對象了。

?
1
2
3
4
5
6
7
8
9
10
public static Singleton getSingleton() {
 if (instance == null) {       //Single Checked
  synchronized (Singleton.class) {
   if (instance == null) {     //Double Checked
    instance = new Singleton();
   }
  }
 }
 return instance ;
}

這段代碼看起來很完美,很可惜它是有問題的。主要在于instance = new Singleton()這句,這并非是一個原子操作,事實上在 JVM 中這句話大概做了下面 3 件事情。

  1. 給 instance 分配內存
  2. 調用 Singleton 的構造函數來初始化成員變量
  3. 將instance對象指向分配的內存空間(執行完這步 instance 就為非 null 了)

但是在 JVM 的JIT編譯器中存在指令重排序的優化。也就是說上面的第二步和第三步的順序是不能保證的,最終的執行順序可能是 1-2-3 也可能是 1-3-2。如果是后者,則在 3 執行完畢、2未執行之前,被線程二搶占了,這時 instance 已經是非 null 了(但卻沒有初始化),所以線程二會直接返回 instance,然后使用,然后順理成章地報錯。為此,我們需要將 instance 變量聲明成 volatile 。

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
public class Singleton {
 private volatile static Singleton instance; //聲明為 volatile
 private Singleton(){}
 public static Singleton getSingleton() {
  if (instance == null) {      
   synchronized (Singleton.class) {
    if (instance == null) { 
     instance = new Singleton();
    }
   }
  }
  return instance;
 }
}

但是特別注意在 Java 1.5 以前的版本使用了 volatile 的雙檢鎖還是有問題的,這個問題在 Java 1.5 中才得以修復,所以在這之后才可以放心使用 volatile。

靜態內部類:IoDH,initialization-on-demand holder

這個模式綜合使用了Java的靜態內部類和多線程缺省同步鎖的知識,很巧妙地同時實現了延遲加載和線程安全。

?
1
2
3
4
5
6
7
8
9
public class Singleton {
 private Singleton() {}
 private static class LazyHolder {
  private static final Singleton INSTANCE = new Singleton();
 }
 public static Singleton getInstance() {   // From wikipedia
  return LazyHolder.INSTANCE;
 }
}

靜態內部類相當于其外部類的static部分,它的對象不依賴于外部類對象,因此可以直接創建。靜態內部類只有在第一次被使用的時候才會被轉載。

多線程缺省同步鎖

 大家都知道,在多線程開發中,為了解決并發問題,主要是通過使用synchronized來加互斥鎖進行同步控制。但是在某些情況中,JVM已經隱含地為您執行了同步,這些情況下就不需要手動進行同步控制了。這些情況包括

   1.由靜態初始化器(在靜態字段上或static{}塊中的初始化器)初始化數據時

 2.訪問final字段時

 3.在創建線程之前創建對象時

 4.線程可以看見它將要處理的對象時

枚舉 Enum

從Java 1.5起,只需編寫一個包含單個元素的枚舉類型:

?
1
2
3
public enum Singleton {
 INSTANCE;
}

這種方法在功能上與公有域方法相近,但是它更加簡潔,無償地提供了序列化機制,絕對防止多次實例化,即使是在面向復雜的序列化或者反射攻擊的時候。雖然這種方法還沒有廣泛采用,但是單元素的枚舉類型以及成為實現Singleton的最佳方法。

--------------------以下是幾個細節存疑的實現方法---------------------

1.static final到底有哪些細節

2.static field處的賦值初始化到底和static代碼塊有先后嗎?

3.靜態內部類的單例模式到底怎么寫

4.P50 in Java EE設計模式解析與應用中的例子真的有Lazyload效果嗎?

以上就是本文的全部內容,希望本文的內容對大家的學習或者工作能帶來一定的幫助,同時也希望多多支持服務器之家!

原文鏈接:http://www.cnblogs.com/echo1937/p/6247050.html

延伸 · 閱讀

精彩推薦
主站蜘蛛池模板: 午夜免费福利视频 | 久久精品中文字幕 | 免费视频一区 | 91视视频在线观看入口直接观看 | 中文字幕色| 亚洲品质自拍视频网站 | 北条麻妃一区二区三区在线观看 | 久久九九国产精品 | 九九亚洲 | 精品国产乱码久久久久久久软件 | 99久久精品免费看国产一区二区三区 | 日韩国产欧美视频 | 亚洲 精品 综合 精品 自拍 | 日韩欧美中文 | 午夜天堂精品久久久久 | 在线播放黄 | 精品久久久久久久久久 | 亚洲免费色 | 成人av免费 | 精品久久网 | 亚洲国产一区在线 | av在线免费播放 | 午夜寂寞少妇aaa片毛片 | 国产成人av综合 | 久久丁香| 久久久久久国产精品mv | 亚洲精品影院 | 91精品久久久久久久久 | 亚洲色图一区二区三区 | 在线欧美日韩 | 综合久久99 | 国产精品久久久久久久 | 国产日韩欧美在线 | 一区二区三区视频 | 一级大片一级一大片 | 亚洲一区二区在线 | 在线观看一区视频 | 久久久精品蜜桃 | 日韩欧美一区视频 | av电影免费在线看 | 亚洲视频在线观看视频 |