並發(五)-單例模式
阿新 • • 發佈:2017-10-28
直接 為什麽 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.主函數是靜態的。
就說這麽多了。。。
並發(五)-單例模式