設計模式之單例模式

單例模式是一種常見的設計模式,並且有幾種不同的寫法,不同的寫法有不同的效果。

1.懶漢式

public class SingletonThread implements Runnable{

	@Override
	public void run() {
		try {
			System.out.println(Singleton.getInstance());
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
	}
}

        這種寫法是最簡單的形式,在第一次調用getInstance方法的時候才實例化,缺點是線程不安全。

測試:

修改Singleton:

public class Singleton {
	private Singleton() {
	};
	private static Singleton singleton = null;
	public static Singleton getInstance() throws InterruptedException {
		if(singleton == null) {
			Thread.sleep(100);// 延遲實例化時間,加強測試效果。
			singleton = new Singleton();
		}
		return singleton;
	}
}

SingletonThread測試類:

public class SingletonThread implements Runnable{

	@Override
	public void run() {
		try {
			System.out.println(Singleton.getInstance()); // 打印得到的Singleton實例hashcode
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
	}
}

Main測試類如下,使用多個線程調用getInstance()方法,

public class Main {

	public static void main(String[] args) throws InterruptedException {
		for(int i = 0; i < 10; i++) {
			SingletonThread s = new SingletonThread();
			Thread t = new Thread(s);
			t.start();
		}
	}
}
運行之後:

com.sj.pattern.Singleton@17823918

com.sj.pattern.Singleton@401e9c3f

com.sj.pattern.Singleton@6150818a

com.sj.pattern.Singleton@610f7612

com.sj.pattern.Singleton@3e10c986

com.sj.pattern.Singleton@4ecac02f

com.sj.pattern.Singleton@4da9ec16

com.sj.pattern.Singleton@5faecf45

com.sj.pattern.Singleton@667262b6

com.sj.pattern.Singleton@19a40cfc

可以看到,生成了10個不同的Singleton實例,懶漢式寫法在多線程環境下可能不會產生真正的單例對象。這樣的問題可以再getInstance()方法之前加synchronized來使線程同步,但是這樣的寫法效率低,並且多線程環境下很少需要同步。

2.餓漢式

public class Singleton {
	private Singleton() {
	};
	private static Singleton singleton = new Singleton();
	public static synchronized Singleton getInstance() {
		if(singleton == null) {
			singleton = new Singleton();
		}
		return singleton;
	}
}
餓漢式是在加載類的時候就生成一個實例,避免了線程不安全。
餓漢式變種寫法:
public class Singleton {
	private Singleton() {};
	private static Singleton singleton = null;
	static {
		singleton = new Singleton();
	}
	public static synchronized Singleton getInstance() {
		if(singleton == null) {
			singleton = new Singleton();
		}
		return singleton;
	}
}

變種寫法的特點在於singleton實例化將在static代碼塊中進行,與上述的區別僅僅在於生成實例的時機不同。並且這兩種方式都沒有實現延遲加載。

3.靜態內部類

public class Singleton {
	private Singleton() {};
	private static class SingletonHolder {
		private static final Singleton INSTANCE = new Singleton();
	}
	public static synchronized Singleton getInstance() {
		return SingletonHolder.INSTANCE;
	}
}
靜態內部類方式採用了ClassLoader的機制保證了INSTANCE實例的單例化,並且可以實現延遲加載,即在真正需要使用INSTANCE的時候才實例化。

4.雙重校驗鎖

public class Singleton {
	private volatile static Singleton singleton = null;
	public static Singleton getInstance() {
		if(singleton == null) {
			synchronized (Singleton.class) {
				if(singleton == null) {
					singleton = new Singleton();
				}
			}
		}
		return singleton;
	}
}
雙重校驗鎖方式是懶漢式的升級版,在多線程環境下可以保證實例的唯一性。

發佈了150 篇原創文章 · 獲贊 7 · 訪問量 28萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章