開發與維運

反射與單例設計模式 | 帶你學《Java語言高級特性》之八十四

上一篇:反射與工廠設計模式 | 帶你學《Java語言高級特性》之八十三
【本節目標】
通過案例引出懶漢式的單例設計模式所出現的問題,並使用使用synchronized關鍵字來處理解決。

反射與單例設計模式

單例設計模式的核心本質在於:類內部的構造方法私有化,在類的內部產生實例化對象後通過static方法獲取實例化對象,進行類中的結構調用,單例設計模式一共有兩類:懶漢式、餓漢式,本節主要來討論懶漢式的單例設計模式。

範例:觀察懶漢式單例設計模式的問題
單線程狀態執行:

public class JavaAPIDemo {
    public static void main(String[] args) throws Exception {
        Singleton sinA = Singleton.getInstance();
        sinA.print();
    }
}
class Singleton {
    private static Singleton instance = null;
    private Singleton() {}
    public static Singleton getInstance() {
        if (instance == null) {
            instance = new Singleton();
        }
        return instance;
    }
    public void print() {
        System.out.println("www.mldn.cn");
    }
}

多線程狀態執行:

public class JavaAPIDemo {
    public static void main(String[] args) throws Exception {
        for (int x = 0; x < 3; x++) {
            new Thread(()->{
                Singleton.getInstance().print();
            },"單例消費端-"+ x).start();
        }
        /**
         * 【單例消費端-0】****** 實例化Singleton類對象 *******
         * 【單例消費端-1】****** 實例化Singleton類對象 *******
         * www.mldn.cn
         * 【單例消費端-2】****** 實例化Singleton類對象 *******
         * www.mldn.cn
         * www.mldn.cn
         */
    }
}
class Singleton {
    private static Singleton instance = null;
    private Singleton() {
        System.out.println("【" + Thread.currentThread().getName() +"】****** 實例化Singleton類對象 *******",Thread.currentThread().getName());
    }
    public static Singleton getInstance() {
        if (instance == null) {
            instance = new Singleton();
        }
        return instance;
    }
    public void print() {
        System.out.println("www.mldn.cn");
    }
}

單例設計模式的最大特點是在整體的運行程序中只允許產生一個實例化對象,但當有了若干個線程之後,實際上當前的程序就會產生多個實例化對象了,此時就不是單例設計模式了。此時問題造成的關鍵在於代碼本身出現了不同步的情況,而要想解決的關鍵就在於同步處理,也就是需要使用synchronized關鍵字。

image.png
單例設計模式問題

範例:修改getInstance()進行同步處理

class Singleton {
    private static Singleton instance = null;
    private Singleton() {
        System.out.println("【" + Thread.currentThread().getName() +"】****** 實例化Singleton類對象 *******",Thread.currentThread().getName());
    }
    public static synchronized Singleton getInstance() {
        if (instance == null) {
            instance = new Singleton();
        }
        return instance;
    }
    public void print() {
        System.out.println("www.mldn.cn");
    }
}

這個時候的確是進行了同步處理,但這個同步處理的代價有些大,因為效率會低。因為整體代碼中實際上只有一塊部分需要進行同步處理,也就是instance對象的實例化處理部分。我們可以知道,之前的同步操作是有些失誤的。

範例:更加合理地進行同步處理

class Singleton {
    private static volatile Singleton instance = null;
    private Singleton() {
        System.out.printf("【" + Thread.currentThread().getName() +"】****** 實例化Singleton類對象 *******",Thread.currentThread().getName());
    }
    public static Singleton getInstance() {
        if (instance == null) {
            synchronized (Singleton.class) {
                if (instance == null) {
                    instance = new Singleton();
                }
            }
        }
        return instance;
    }
    public void print() {
        System.out.println("www.mldn.cn");
    }
}

面試題:請編寫單例設計模式
直接編寫一個餓漢式的單例設計模式,並且實現構造方法私有化;
在Java中哪裡使用到了單例設計模式?
Runtime類、Pattern類、Spring框架;
懶漢式單例模式的問題
即上面描述所出現的問題。
單例設計模式的最大特點是在整體的運行程序中只允許產生一個實例化對象,但當有了若干個線程之後,實際上當前的程序就會產生多個實例化對象了,此時就不是單例設計模式了。此時問題造成的關鍵在於代碼本身出現了不同步的情況,而要想解決的關鍵就在於同步處理,也就是需要使用synchronized關鍵字。

想學習更多的Java的課程嗎?從小白到大神,從入門到精通,更多精彩不容錯過!免費為您提供更多的學習資源。
本內容視頻來源於阿里雲大學

更多Java面向對象編程文章查看此處

Leave a Reply

Your email address will not be published. Required fields are marked *