首頁 > 軟體

Java中常用的設計模式之單例模式詳解

2022-02-27 19:00:17

注意

1、單例類只能有一個範例。

2、單例類必須自己建立自己的唯一範例。

3、單例類必須給所有其他物件提供這一範例。

優點

1.在記憶體裡只有一個範例,減少了記憶體的開銷,尤其是頻繁的建立和銷燬範例(比如管理學院首頁頁面快取)。

2.避免對資源的多重佔用(比如寫檔案操作)。

缺點

1.沒有介面,不能繼承,與單一職責原則衝突,一個類應該只關心內部邏輯,而不關心外面怎麼樣來範例化。

使用場景

1.要求生產唯一序列號。

2.WEB 中的計數器,不用每次重新整理都在資料庫里加一次,用單例先快取起來。

3.建立的一個物件需要消耗的資源過多,比如 I/O 與資料庫的連線等。

一、實現方式

package com.asurplus.common.singleton.style1;
import lombok.extern.slf4j.Slf4j;
import java.util.Objects;
@Slf4j
public class ResUtils {
    private volatile static ResUtils instance = null;
    /**
     * 私有的構造方法
     */
    private ResUtils() {
    }
    /**
     * 提供獲取範例的方法
     *
     * @return
     */
    public static ResUtils getInstance() {
        // 為空才建立
        if (Objects.isNull(instance)) {
            // 避免並行操作時
            synchronized (ResUtils.class) {
                // 為空才建立
                if (Objects.isNull(instance)) {
                    // 建立新物件
                    instance = new ResUtils();
                    log.info("建立了物件");
                }
            }
        }
        return instance;
    }
}

我們將其構造方法私有化,從而外部無法建立範例,並且我們提供了獲取唯一範例的方法,這樣我們就能從外部得到該範例。

二、實現方式

package com.asurplus.common.singleton.style2;
import lombok.extern.slf4j.Slf4j;
@Slf4j
public class ResUtils2 {
    /**
     * 靜態內部類
     */
    private static class ResUtils2Holder {
        private static ResUtils2 instance = new ResUtils2();
    }
    /**
     * 提供獲取範例的方法
     *
     * @return
     */
    public static ResUtils2 getInstance() {
        return ResUtils2Holder.instance;
    }
}

我們使用靜態內部類的方法建立範例,因為 JVM 只會載入一次的原理,所以最終只會建立一個範例,並且提供了獲取範例的方法,這樣我們就能從外部得到該範例。

三、測試

package com.asurplus.common.singleton;
import com.asurplus.common.singleton.style1.ResUtils;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
/**
 * 單例模式
 */
public class TestMain {
    public static void main(String[] args) {
        // 建立執行緒池
        ExecutorService executorService = Executors.newFixedThreadPool(10);
        for (int i = 0; i < 100; i++) {
            executorService.execute(ResUtils::getInstance);
        }
        executorService.shutdown();
    }
}

輸出結果

可以看出,我們獲取了 100 次範例,只建立了一個範例,從而實現了我們的單例模式。

總結

本篇文章就到這裡了,希望能夠給你帶來幫助,也希望您能夠多多關注it145.com的更多內容!  


IT145.com E-mail:sddin#qq.com