劍指offer 面試題2—實現單例模式

終於把簡直offer看完了一遍

所以第二遍我決定要美一個題自己去實現一遍,會加入自己的理解(但是不一定對哈)

題目:設計一個類,我們只能生成該類的一個實例。

餓漢試

package T2Singleton;

/**
 * 餓漢式
 * @author yxx
 *
 */
public class Singleton {

    //私有構造方法
    private Singleton() {}

    private static Singleton singleton = new Singleton();

    public static Singleton getInstance() {
        return singleton;
    }

}

我第一下想到的就是餓漢試的單例模式,因爲他可以在多線程下使用,不想一般的懶漢式那樣。

餓漢式在類創建的同時就已經創建好一個靜態的對象供系統使用,以後不再改變,所以是線程安全的。

如果是懶漢式,我們就得加同步鎖了

懶漢式

考慮同步,但是是對方法加鎖

package T2Singleton;

/**
 * 多線程
 * 
 * @author yxx
 * 
 */
public class Singleton2 {

    //私有構造方法
    private Singleton2() {}

    private static Singleton2 instance = null;

    public synchronized static Singleton2 getInstance() {
        if (instance == null) {
            instance = new Singleton2();
        }
        return instance;
    }
}

考慮同步,對對象上鎖,使鎖的粒度變小

package T2Singleton;

/**
 * 多線程
 * 
 * @author yxx
 * 
 */
public class Singleton2 {

    // 私有構造方法
    private Singleton2() {}
    private static Singleton2 instance = null;

    public static Singleton2 getInstance() {
        if (instance == null) {
            synchronized (instance) {
                if (instance == null) {
                    instance = new Singleton2();
                }
            }
        }
        return instance;
    }
}

上面這種,加同步鎖前後兩次判斷實例是否存在
加鎖耗時。可以實現只有當single爲null即沒有創建時,需要加鎖操作,當single創建出來之後,則無須加鎖。

還有一種登記式的,有興趣可以自行研究一下

package T2Singleton;

/**
 * 按需創建
 * 
 * @author yxx
 * 
 */
public class Singleton3 {

    Singleton3() {}

    public static Singleton3 getInstance() {
        return Nested.instance;
    }

    static class Nested {

        Nested() {}

        final static Singleton3 instance = new Singleton3();

    }
}

如果當我們第一次試圖通過屬性Single3.instance得到Single3的實例時,會自動調用Nested的靜態構造函數創建實例instance。如果我們不調用屬性,那麼就不會觸發運行,也不會創建實例。

餓漢式和懶漢式區別

這兩種乍看上去非常相似,其實是有區別的,主要兩點

1、線程安全:

餓漢式是線程安全的,可以直接用於多線程而不會出現問題,懶漢式就不行,它是線程不安全的,如果用於多線程可能會被實例化多次,失去單例的作用。
如果要把懶漢式用於多線程,有兩種方式保證安全性,一種是在getInstance方法上加同步,另一種是在使用該單例方法前後加雙鎖。

2、資源加載:

餓漢式在類創建的同時就實例化一個靜態對象出來,不管之後會不會使用這個單例,會佔據一定的內存,相應的在調用時速度也會更快,
而懶漢式顧名思義,會延遲加載,在第一次使用該單例的時候纔會實例化對象出來,第一次掉用時要初始化,如果要做的工作比較多,性能上會有些延遲,之後就和餓漢式一樣了。

所有源碼均可去【GitHub】下載

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章