1. 程式人生 > >並發(五)-單例模式

並發(五)-單例模式

直接 為什麽 style 第一個 接下來 cnblogs get 外部 就是

這裏系統的說一下單例模式。

本文參考的文章,地址如下:

微信公眾號:Java後端技術

文章:Java多線程編程-(12)-單例模式幾種寫法的錯與對

作者:徐劉根

主要是四大類:餓漢、懶漢、雙重校驗鎖DCL、

1.餓漢模式

示例如下:

 1 public class Singleton {
 2 
 3     /*為了防止外部訪問,所以實例是private的
 4     為了在static方法中訪問,所以必須是static
 5     至於為什麽,叫餓漢模式。我想,因為在程序走到下面這一行時,
 6     會初始化,調用構造方法。在沒有調用getInstance方法時,就創建好了實例。
7 因為,可能叫做餓漢模式吧*/ 8 private static Singleton singleton = new Singleton(); 9 10 private Singleton() { 11 System.out.println("666"); 12 } 13 public static Singleton getInstance() { 14 return singleton; 15 } 16 }

2.懶漢模式

示例如下:

 1 public class SingletonByLazy {
2 3 private static SingletonByLazy singleton; 4 5 /*這裏必須是private修飾符,否則,就可以new多個對象,這是單例模式最基本的保證*/ 6 private SingletonByLazy() {} 7 8 /*需要註意的是,必須加上synchronized關鍵字。否則會導致對象的訪問變得不安全。 9 * 餓漢的優點是延遲加載,在你需要的時候進行加載。缺點是必須使用同步*/ 10 public static synchronized SingletonByLazy getInstance() {
11 if (singleton == null) { 12 singleton = new SingletonByLazy(); 13 } 14 return singleton; 15 } 16 }

3.雙重校驗鎖DCL

代碼比上面兩種多一些,繞一些,但是思想還是值得學習的嘛!看下面的例子:

 1 public class SingletonByDCL {
 2 
 3     /*這裏切記,volatile關鍵字不可以缺少。
 4      * 不然會因為指令重排,導致在第一個判空時,將未初始化的對象返回。*/
 5     private volatile static SingletonByDCL singleton;
 6     
 7     /*這裏必須是private修飾符,否則,就可以new多個對象,這是單例模式SingletonByLazy.java最基本的保證*/
 8     private SingletonByDCL() {}
 9     
10     /*需要註意的是,必須加上synchronized關鍵字。否則會導致對象的訪問變得不安全。
11      * 餓漢的優點是延遲加載,在你需要的時候進行加載。缺點是必須使用同步*/
12     public static SingletonByDCL getInstance() {
13         if (singleton == null) {
14             synchronized (SingletonByDCL.class) {
15                 if (singleton == null) {
16                     singleton = new SingletonByDCL();
17                 }
18             }
19         }
20         return singleton;
21     }
22 }

4.靜態內部類

 1 public class SingletonByStaticClass {
 2 
 3     /*通過類加載機制,保證創建單一對象*/
 4     private static class SingletonHolder {
 5         private static final SingletonByStaticClass single = new SingletonByStaticClass();
 6     }
 7     
 8     private SingletonByStaticClass() {}
 9     
10     /*對於JAVA的加載機制來說,當第一次訪問類的靜態字段時,會觸發類的加載*/
11     public static SingletonByStaticClass getInstance() {
12         return SingletonHolder.single;
13     }
14 }

接下來,我要單獨說一下static關鍵字。因為非常重要。

小例子:

 1 public class Test {
 2 
 3     public void method01(){
 4         System.out.println("method01");
 5     }
 6     
 7     public static void method02(){
 8         System.out.println("method02");
 9     }
10     
11     public static void main(String args[]){
12         new Test().method01();
13         method02();
14     }
15 }
16 
17 
18 執行結果:
19 method01
20 method02

例子很簡單,但是要說明的地方是:靜態方法中不能直接調用非靜態方法。

為什麽呢?首先static的成員是在類加載的時候初始化的,而非static的成員是在創建對象的時候初始化的。先後順序是,先加載才能初始化。那麽加載的時候,初始化static成員,非static成員是在創建對象的時候初始化的。也就是說,static屬於類,而非static屬於對象。

下面說static的特點:

1.隨著類的加載而加載,隨著類的消失而消失(能消失嗎? 這裏我有疑問,有待驗證)。

2.靜態先存在,對象後存在。

3.被所有對象共享。

4.直接調用

使用時註意事項:

1.靜態方法只能方法靜態成員。

2.靜態方法中不能使用super this 關鍵字。原因呢,上方的解釋,懂了的話,這一點自然就明白了。

3.主函數是靜態的。

就說這麽多了。。。

並發(五)-單例模式