[轉]設計模式--單例模式(一)懶漢式和餓漢式
餓漢式的特點是一開始就加載了,如果說懶漢式是“時間換空間”,那麽餓漢式就是“空間換時間”,因為一開始就創建了實例,所以每次用到的之後直接返回就好了。
讓我們先看下代碼:
懶漢式:
//懶漢式單例模式
//懶漢式單例模式 public class MySingleton { //設立靜態變量 private static MySingleton mySingleton = null; private MySingleton(){ //私有化構造函數 System.out.println("-->懶漢式單例模式開始調用構造函數"); } //開放一個公有方法,判斷是否已經存在實例,有返回,沒有新建一個在返回 public static MySingleton getInstance(){ System.out.println("-->懶漢式單例模式開始調用公有方法返回實例"); if(mySingleton == null){ System.out.println("-->懶漢式構造函數的實例當前並沒有被創建"); mySingleton = new MySingleton(); }else{ System.out.println("-->懶漢式構造函數的實例已經被創建"); } System.out.println("-->方法調用結束,返回單例"); return mySingleton; } }
public class Client { /** * 懶漢式單例模式 * MySingleton */ public static void myprint(){ System.out.println("-----------------懶漢式單例模式----------------"); System.out.println("第一次取得實例(懶漢式)"); MySingleton s1 = MySingleton.getInstance(); System.out.println("第二次取得實例(懶漢式)"); MySingleton s2 = MySingleton.getInstance(); if(s1==s2){ System.out.println(">>>>>s1,s2為同一實例(懶漢式)<<<<<"); } System.out.println(); } /** * @param args */ public static void main(String[] args) { // TODO Auto-generated method stub //懶漢式 myprint(); //餓漢式 //myprint2(); //懶漢式改進 //myprint2a(); //登記式 //myprint3(); } }
-----------------懶漢式單例模式---------------- 第一次取得實例(懶漢式),懶漢式單例模式開始調用公有方法返回實例, 懶漢式構造函數的實例當前並沒有被創建懶漢式單例模式開始調用構造函數 ,方法調用結束,返回單例 第二次取得實例(懶漢式) ,懶漢式單例模式開始調用公有方法返回實例 ,懶漢式構造函數的實例已經被創建 ,方法調用結束,返回單例 s1,s2為同一實例(懶漢式)
可以看出,在第一次調用公有方法的時候,並沒有實例,所以我們創建了一個實例,之後再訪問的時候,因為已經有一個已經創建好的實例,所以直接返回了。
餓漢式:
- //餓漢式單例模式
- public class MySingleton2 {
- //設立靜態變量,直接創建實例
- private static MySingleton2 mySingleton = new MySingleton2();
- private MySingleton2(){
- //私有化構造函數
- System.out.println("-->餓漢式單例模式開始調用構造函數");
- }
- //開放一個公有方法,判斷是否已經存在實例,有返回,沒有新建一個在返回
- public static MySingleton2 getInstance(){
- System.out.println("-->餓漢式單例模式開始調用公有方法返回實例");
- return mySingleton;
- }
- }
//餓漢式單例模式 public class MySingleton2 { //設立靜態變量,直接創建實例 private static MySingleton2 mySingleton = new MySingleton2(); private MySingleton2(){ //私有化構造函數 System.out.println("-->餓漢式單例模式開始調用構造函數"); } //開放一個公有方法,判斷是否已經存在實例,有返回,沒有新建一個在返回 public static MySingleton2 getInstance(){ System.out.println("-->餓漢式單例模式開始調用公有方法返回實例"); return mySingleton; } }看下客戶端的測試代碼:
/** * 餓漢式單例模式 * MySingleton2 */ public static void myprint2(){ System.out.println("-----------------餓漢式單例模式----------------"); System.out.println("第一次取得實例(餓漢式)"); MySingleton2 s1 = MySingleton2.getInstance(); System.out.println("第二次取得實例(餓漢式)"); MySingleton2 s2 = MySingleton2.getInstance(); if(s1==s2){ System.out.println(">>>>>s1,s2為同一實例(餓漢式)<<<<<"); } System.out.println(); }
/** * @param args */ public static void main(String[] args) { // TODO Auto-generated method stub //懶漢式 //myprint(); //餓漢式 myprint2(); //懶漢式改進 //myprint2a(); //登記式 //myprint3(); }
輸出結果為:
-----------------餓漢式單例模式---------------- 第一次取得實例(餓漢式) -->餓漢式單例模式開始調用構造函數 -->餓漢式單例模式開始調用公有方法返回實例 第二次取得實例(餓漢式) -->餓漢式單例模式開始調用公有方法返回實例 >>>>>s1,s2為同一實例(餓漢式)<<<<<
總結一下,兩種方案的構造函數和公用方法都是靜態的(static),實例和公用方法又都是私有的(private)。但是餓漢式每次調用的時候不用做創建,直接返回已經創建好的實例。這樣雖然節省了時間,但是卻占用了空間,實例本身為static的,會一直在內存中帶著。懶漢式則是判斷,在用的時候才加載,會影響程序的速度。最關鍵的是,在並發的情況下,懶漢式是不安全的。如果兩個線程,我們稱它們為線程1和線程2,在同一時間調用getInstance()方法,如果線程1先進入if塊,然後線程2進行控制,那麽就會有兩個實例被創建。
[轉]設計模式--單例模式(一)懶漢式和餓漢式