單例模式,很多種方式實作,但是這兒隻介紹最優方案。
就是利用内部類去實作單例模式。
這種單例模式的好處就是,延遲加載,減少記憶體開銷,通路成本低且線程安全。
直接上代碼:
/**
* @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>()方法中 有耗時很長的操作,就可能造成多個線程阻塞,在實際應用中這種阻塞往往是隐藏的。
這裡其實是驗證小測試,看看運作結果,就懂了吧: