天天看點

JAVA設計模式(一)單例模式1.介紹2.應用場景3.實作方式

JAVA設計模式(一)單例模式1.介紹2.應用場景3.實作方式

1.介紹

單例模式是一種對象建立型模式,保證一個類隻有一個執行個體,其私有化構造方法公開一個全局通路的代理方法。

2.應用場景

  • 作業系統的任務管理器
  • 讀取配置檔案的類
  • 資料庫連接配接池
  • Javaweb 中的 Servlet 執行個體
  • Spring 建立的執行個體,預設為單例

3.實作方式

/**
 * 餓漢式單例
 */
public class EagerSingleton {

    private static EagerSingleton eagerSingleton = new EagerSingleton();

    private EagerSingleton() {

    }

    public static EagerSingleton getInstance() {
        return eagerSingleton;
    }
}
           

優點:線程安全,不用加同步鎖,是以在高并發時調用效率高。

缺點:不能懶加載,如果不使用該類的執行個體,浪費記憶體資源。

/**
 * 懶漢式
 */
public class LazySingleton {

    private static LazySingleton lazySingleton;

    private LazySingleton() {

    }

    public static LazySingleton getInstance() {
        if (lazySingleton == null) {
            lazySingleton = new LazySingleton();
        }
        return lazySingleton;
    }
}
           

優點:實作懶加載,合理利用系統資源。

缺點:需要添加同步鎖,高并發時調用效率不高。

(注意:懶漢式可以通過反射機制建立多個執行個體。)

public class SingletonTest {
    public static void main(String[] args)throws Exception {
        Class<?> clazz = Class.forName("com.design.singleton.LazySingleton");
        Constructor<?> constructor = clazz.getDeclaredConstructor(null);

        // 跳過檢測機制
        constructor.setAccessible(true);

        LazySingleton lazySingleton1 = (LazySingleton) constructor.newInstance();

        LazySingleton lazySingleton2 = (LazySingleton) constructor.newInstance();

        System.out.println(lazySingleton1 == lazySingleton2);// 結果傳回 false
    }
}
           

優化方式:

public class Optimizing {

    private Optimizing() {

    }

    private static class innerSingleton{
        private static final Optimizing optimizing1 = new Optimizing();
    }

    public static Optimizing getInstance() {
        return innerSingleton.optimizing1;
    }
}
           

外部類沒有靜态屬性,是以不會像餓漢式立即加載對象。

隻有當調用公共方法(getInstance)時,才會加載靜态内部類。加載内部類的過程是線程安全的。

内部類中通過 static final 確定記憶體中隻有一個外部類的執行個體,因為執行個體變量(optimizing1)隻能被指派一次。

測試:

測試結果是相對的,硬體等環境的不同會有影響,大緻上的性能比例差不多。

public static void main(String[] args) throws Exception {
        // 線程數
        int num = 10;
        // 計數器
        CountDownLatch cd = new CountDownLatch(num);
        long t1 = System.currentTimeMillis();
        for (int i = 0; i < num; i++) {
            new Thread(new Runnable() {
                @Override
                public void run() {
                    for (int i = 0; i < 100000; i++) {
                        // 此處替換不同實作方式的單例代碼進行測試
//                        EagerSingleton eagerSingleton = EagerSingleton.getInstance();//耗時:17ms
//                        LazySingleton lazySingleton =LazySingleton.getInstance();//耗時:19ms
//                        Optimizing optimizing = Optimizing.getInstance();//耗時:17ms
                    }
                    cd.countDown();
                }
            }).start();
        }
        // 主線程等待
        cd.await();
        System.out.println("耗時:" + (System.currentTimeMillis() - t1) + "ms");
    }