天天看點

單例模式 之内部類延遲加載,(多)線程安全

單例模式,很多種方式實作,但是這兒隻介紹最優方案。

就是利用内部類去實作單例模式。

這種單例模式的好處就是,延遲加載,減少記憶體開銷,通路成本低且線程安全。

直接上代碼:

/**
 * @Author : JCccc
 * @CreateTime : 2018-11-5
 * @Description :
 * @Point: Keep a good mood
 **/

public class SingletonInner {




//    靜态嵌套類(Static Nested Class)和内部類(Inner Class)的不同
//    靜态嵌套類是被聲明為靜态(static)的内部類,可以不依賴于外部類被執行個體化,
//    内部類需要在外部類執行個體化後才能執行個體化.


    /**
     * 内部類實作單例模式
     * 延遲加載,減少記憶體開銷
     */

    /**
     * 在内部類SingletonHolder 第一次被加載的時候,建立了instance,指向SingletonInner的執行個體。
     */
    private static class SingletonHolder {
        private static SingletonInner instance = new SingletonInner();
    }

    /**
     * 私有的構造函數
     */
    private SingletonInner() {
        System.out.println("Singleton is create");
    }

    public static SingletonInner getInstance() {

        return SingletonHolder.instance;
    }

    public void method() {
        System.out.println("SingletonInner!");
    }



    public static void main(String[] args) {
        SingletonInner Single_dog1 = SingletonInner.getInstance();
        SingletonInner Single_dog2 = SingletonInner.getInstance();
        SingletonInner Single_dog3 = SingletonInner.getInstance();
        System.out.println(Single_dog1+"\n"+Single_dog2+"\n"+Single_dog3);


        


    }
}      

 針對内部類為何能保證線程安全,實作延遲加載,下面是簡要的說明:

   private static class SingletonHolder {

        private static SingletonInner instance = new SingletonInner();

    }

     這個内部類因為被static修飾,代表,這個貨是一個類級别的内部類。

     如果沒有被static修飾,就是一個對象級别的内部類,這種内部類是必須綁定在外部對象執行個體上的

     這種類級别内部類的好處是什麼,就是虛拟機JVM的内部機制對它是有保護的,隻允許它第一次被加載,其餘都是互斥的。

 虛拟機會保證一個類的類構造器<clinit>()在多線程環境中被正确的加鎖、同步,如果多個線程同時去初始化一個類,那麼隻會     有一個線程去執行這個類的類構造器<clinit>(),其他線程都需要阻塞等待,直到活動線程執行<clinit>()方法完畢。

   特别需要注意的是,在這種情形下,其他線程雖然會被阻塞,但如果執行<clinit>()方法的那條線程退出後,其他線程在喚醒之     後不會再次進入/執行<clinit>()方法,因為 在同一個類加載器下,一個類型隻會被初始化一次。如果在一個類的<clinit>()方法中     有耗時很長的操作,就可能造成多個線程阻塞,在實際應用中這種阻塞往往是隐藏的。

這裡其實是驗證小測試,看看運作結果,就懂了吧:

繼續閱讀