Java【設計模式】單例模式七種實現方式(附原始碼)

2020-10-20 11:00:01

單例模式介紹

所謂類的單例模式設計,就是採取一定的方法保證在整個系統中,對某個類只能存在一個物件範例,並且該類只提供一個取得其物件範例的方法(靜態)

單例模式常用實現方式

餓漢式

步驟如下:

  1. 構造方法私有化
  2. 類內建立物件(建立就進行範例化)
  3. 向外提供一個靜態公共方法
public class SingletonTest01 {
	public static void main(String[] args) {
		Singleton st=Singleton.getInstance();//類裝載時便進行範例化
		Singleton st2=Singleton.getInstance();
		System.out.println(st==st2);
		System.out.println(st.hashCode());
		System.out.println(st2.hashCode());
	}
}
class Singleton{
	
	//餓漢式
	//1.構造器私有化
	private Singleton()
	{
	}
	//2.本類內部建立物件範例
	private final static Singleton instance =new Singleton();
	//3。提供一個公有靜態方法
	public static Singleton getInstance()
	{
		return instance;
	}
}

優點:執行緒安全(實現同步)
缺點:傳引數困難,且容易造成記憶體浪費(裝載即範例,但是有可能用不到)

懶漢式

步驟如下:

  1. 構造方法私有化
  2. 類內建立物件
  3. 向外提供一個靜態公共方法(需要判斷是否非空)
public class SingletonTest03 {
	public static void main(String[] args) {
		System.out.println("執行緒不安全!!!!");
		Singleton st=Singleton.getInstance();//類裝載時便進行範例化
		Singleton st2=Singleton.getInstance();
		System.out.println(st==st2);
		System.out.println(st.hashCode());
		System.out.println(st2.hashCode());
	}
}
class Singleton{
	private static Singleton instance;
	private Singleton()
	{
	}
	public static Singleton getInstance()
	{
		if(instance==null)
			instance=new Singleton();
		return instance;
	}
	
}

優點:延遲載入
缺點:執行緒不安全(多執行緒下,若一個執行緒進入了if(singleton==null)判斷語句塊,還未來得及往下執行,另一個執行緒也通過了這個判斷語句,這時便會產生多個範例)

同步方法

synchronized同步方法,每一次只允許一個執行緒存取。

public class SingletonTest04 {
	public static void main(String[] args) {
		Singleton st=Singleton.getInstance();
		Singleton st2=Singleton.getInstance();
		System.out.println(st==st2);
		System.out.println(st.hashCode());
		System.out.println(st2.hashCode());
	}

}
class Singleton{
	private static Singleton instance;
	private Singleton()
	{
		
	}
	public static synchronized Singleton getInstance()
	{
		//此方法效率低下
		if(instance==null)
			instance=new Singleton();
		return instance;
	}
}

優點:解決了執行緒不安全的問題
缺點:效率太低(每個執行緒在想獲得類的範例的時候,執行getInstance()方法都要進行同步。其實只執行一次程式碼範例化就足夠了。)

同步程式碼塊
class Singleton
{
	private static Singleton instance;
	private Singleton()
	{
		
	}
	public static Singleton getInstance()
	{
		if(instance==null)
		{
			synchronized(Singleton.class)
			{
				instance=new Singleton();
			}
		}
		return instance;
	}
}

寫法錯誤,同步並不能起到真正的作用,實際開發不可用。

雙重檢查
class Singleton{
	private static volatile Singleton instance;
	private Singleton()
	{
		
	}
	public static synchronized Singleton getInstance()
	{
		if(instance==null)//解決了效率低下
		{
			synchronized(Singleton.class)
			{
				if(instance==null)//雙重檢查,實現一次範例化
				{
					instance=new Singleton();
				}
			}
		}
		return instance;
	}
}

實現了延時載入,與執行緒安全,同時保證了效率。

靜態內部類

class Singleton
{
	private static volatile Singleton instance;
	private Singleton()
	{
	}
	//外類裝載不會馬上裝載的
	private static class SingletonInstance{
		private static final Singleton Instance=new Singleton();//餓漢式
	}
	//用到他的時候才裝載(JVM裝載時執行緒安全)
	public static synchronized Singleton getInstance()
	{
		return SingletonInstance.Instance;//懶漢式
	}
}

優點:

  1. 這種方法採用了類裝載的機制來保證初始化範例時只有一個執行緒。
  2. 靜態內部類在Singleton進行裝載時並不會立即範例化,而是在需要進行範例化時,呼叫getInstance()方法,才會裝載SingletonInstance類,從而完成範例化。
  3. 類的靜態屬性只會在第一次載入類的時候初始化,JVM保證了執行緒的安全,在類進行初始化時,別的執行緒是無法進入的。
    這種方法也實現了延時載入與執行緒安全

列舉方式

public class SingletonTest08 {
	public static void main(String[] args) {
		Singleton st=Singleton.Instance;
		Singleton st2=Singleton.Instance;
		System.out.println(st==st2);
		System.out.println(st.hashCode());
		System.out.println(st2.hashCode());
	}

}
enum Singleton{//列舉實現單利
	Instance;//屬性
	public void sayOK()
	{
		System.out.println("ok~");
	}
}

優點:
列舉方式實現單例,不僅能夠避免多執行緒同步問題,而且還能防止反序列化重新建立新的物件。