天天看點

設計模式:單例模式的寫法(基礎寫法和線程安全寫法)

單例模式的寫法很多,先給出一種最基礎的寫法:

(A種寫法):

package singleton;

public class SingletonInstance {

	private static SingletonInstance mSingletonInstance = null;

	// 特意将構造函數設定成 private,防止外部使用者new SingletonInstance()。
	private SingletonInstance() {

	}

	public static SingletonInstance getInstance() {
		if (mSingletonInstance == null) {
			mSingletonInstance = new SingletonInstance();
		}

		return mSingletonInstance;
	}
}
           

A寫法是單例模式最簡單、最基礎、最清晰的寫法,但遺憾的是這種寫法是線程不安全的代碼寫法。假設該類同時在并發N多個線程中被通路被使用、尤其是如果這個類如果涉及到資料庫通路等等此類線程安全問題敏感的代碼應用場景時,後果将是一場災難。

但單例模式的A種寫法也有其廣泛場景:不要求線程安全,沒有同步需求且效率優先級高的場景中,推薦使用單例模式的A種寫法。

B種寫法(線程安全寫法1):

package singleton;

public class SingletonInstance {

	private static SingletonInstance mSingletonInstance = null;

	// 特意将構造函數設定成 private,防止外部使用者new SingletonInstance()。
	private SingletonInstance() {

	}

	public static synchronized SingletonInstance getInstance() {
		if (mSingletonInstance == null) {
			mSingletonInstance = new SingletonInstance();
		}

		return mSingletonInstance;
	}
}
           

單例模式的B種寫法其實是在A種寫法的基礎上的改進,要點是增加了同步機制:synchronized。synchronized ,同步從某種意義上講其實就是阻塞,阻塞的結果就是任意時刻,隻有一個線程可以通路該段同步方法體中的代碼。這樣被synchronized的代碼性能将下降,但達到了線程安全的目的。

B種單例模式的寫法,主要是為了解決線程安全。變體很多,變體的目的主要集中在如何增強線程安全的操作性。現舉例如下,比如:

B種寫法的增強型變體(線程安全寫法2):

package singleton;

public class SingletonInstance {

	// 注意!volatile 也不能完全保證線程安全,後面将寫關于volatile的文章解釋這一點兒。
	// volatile隻是增強。
	private static volatile SingletonInstance mSingletonInstance = null;

	// 特意将構造函數設定成 private,防止外部使用者new SingletonInstance()。
	private SingletonInstance() {

	}

	public static SingletonInstance getInstance() {
		if (mSingletonInstance == null) {

			// synchronized (SingletonInstance.class)不必鎖住整個方法,隻鎖住一塊代碼即可。
			// 和synchronized (this)一樣,但因為是static方法,故無法使用this,才使用XXXClass.class
			// synchronized的基本使用原則:盡可能不要鎖住大塊大塊代碼(方法體或類),隻鎖住必需的一小塊核心、急需同步的代碼段即可,越少越好,越小越好。
			// 要知道,一旦使用synchronized,就意味着代碼性能的開銷
			synchronized (SingletonInstance.class) {
				if (mSingletonInstance == null)
					mSingletonInstance = new SingletonInstance();
			}
		}

		return mSingletonInstance;
	}
}