單例設(shè)計模式基本上是用來控制創(chuàng)建許多對象,因此屬于家庭創(chuàng)建模式来吩。
早期的趨勢是創(chuàng)建一個馬克斯的對象,但在某些情況下,我們需要一個固定數(shù)量的對象; 這種模式是正確的,來幫助我們圈纺。 通常,我們構(gòu)造函數(shù)標(biāo)記為私有,以確保外部世界不能創(chuàng)建對象,提供了一個靜態(tài)方法,簡單地返回對象。 它創(chuàng)建一個物體只有在沒有事先創(chuàng)建内颗。
隨著時間的推移,人們意識到這種香草的實現(xiàn)單例,幾個問題,這是改善來解決這些問題。 注意,單件不對錯; 只要適合你的問題域敦腔。
在這次演講中,我們將看看不同實現(xiàn)的單例均澳。
讓我們看看類圖:
單使用
有幾個地方是明智的使用單例模式。 例如:日志記錄符衔、緩存找前、負(fù)載平衡、配置判族、通信(IO避免表現(xiàn)不佳或遠(yuǎn)程)和數(shù)據(jù)庫連接池躺盛。 單例的Java API的一個例子是運(yùn)行時類。
單例實現(xiàn)
這是香草的方式使用一個立即加載機(jī)制,實現(xiàn)一個單例是線程安全的形帮。
public class MySingleton {
private static final MySingleton mySingleton = new MySingleton();
private MySingleton(){}
public static MySingleton getInstance(){
return mySingleton;
}
}
另一方面,這里有一個例子使用延遲加載機(jī)制實現(xiàn)單例槽惫。 在多線程應(yīng)用程序中,這將是一個糟糕的方法。
class MySingleton {
private static MySingleton mySingleton;
private MySingleton(){}
public static MySingleton getInstance(){
if(null == mySingleton) {
mySingleton = new MySingleton();
}
return mySingleton;
}
}
一個多線程的方法可以避免競態(tài)條件,以確保它不會違反一個單例的哲學(xué)辩撑。 但是在下面的例子中,使整個方法“同步”并不是一個好方法,因為我們需要把鎖對象創(chuàng)建語句界斜。
class MySingleton {
private static MySingleton mySingleton;
private MySingleton(){}
public synchronized static MySingleton getInstance(){
if(null == mySingleton) {
mySingleton = new MySingleton();
}
return mySingleton;
}
}
下面的多線程的實現(xiàn)方式可以避免競態(tài)條件,以確保它不會違反獨立的哲學(xué)和雙重檢查鎖定的幫助下使用對象級別的鎖會達(dá)到相同的。 這個實現(xiàn)保證線程安全; 但一直鎖所需的額外的對象是這不是一個很好的實踐合冀。 另一個缺點是,有人可以使用類級別鎖你的鎖的優(yōu)點是在一個不同的對象
class MySingleton {
private static MySingleton mySingleton;
private static final Object lock = new Object();
private MySingleton(){}
public static MySingleton getInstance(){
if(null == mySingleton) {
synchronized(lock) {
if(null == mySingleton) {
mySingleton = new MySingleton();
}
}
}
return mySingleton;
}
}
另一個multi-threaded-based實現(xiàn)(避免競態(tài)條件)的幫助下可以實現(xiàn)雙重檢查鎖定使用類級別鎖锄蹂。 在這里,將MySingleton對象標(biāo)記為不穩(wěn)定將確保變化由一個線程應(yīng)該在另一個是可見的。 這個實現(xiàn)保證線程安全水慨。
class MySingleton {
private volatile static MySingleton mySingleton;
private MySingleton() {}
public static MySingleton getInstance() {
if (null == mySingleton) {
synchronized(MySingleton.class) {
if (null == mySingleton) {
mySingleton = new MySingleton();
}
}
}
return mySingleton;
}
}
這意味著實現(xiàn)提供了一個聰明的構(gòu)造函數(shù),將停止單合同違反使用反射得糜。
class MySingleton {
private volatile static MySingleton mySingleton;
//Reflection can't hack to create more than one object.
private MySingleton() throws Exception {
if (null == mySingleton) {
mySingleton = new MySingleton();
} else {
throw new Exception("It's a singleton class; don't expect more object to get produced");
}
}
public static MySingleton getInstance() throws Exception {
if (null == mySingleton) {
synchronized(MySingleton.class) {
if (null == mySingleton) {
mySingleton = new MySingleton();
}
}
}
return mySingleton;
}
}
這是一個非常受歡迎的實現(xiàn)使用一個靜態(tài)類,這帶來了延遲加載和線程安全的權(quán)力。
public class MySingleton {
private MySingleton() {}
private static class SingletonUisngInner {
private static MySingleton mySingleton = new MySingleton();
}
public static MySingleton getInstance() {
return SingletonUisngInner.mySingleton;
}
}
在某些情況下,如果你的單例類繼承接口可克隆屬性,那么你的單例類需要格外小心,防止單例設(shè)計合同晰洒。 你的單例類應(yīng)該覆蓋的克隆方法和顯式地拋出CloneNotSupportedException朝抖。
class ClonedClass implements Cloneable {
//Some logic
public Object clone() throws CloneNotSupportedException {
return super.clone();
}
}
public class MySingleton extends ClonedClass {
private MySingleton() {}
private static class SingletonUisngInner {
private static MySingleton mySingleton = new MySingleton();
}
public static OneMore getInstance() {
return singletonUisngInner.mySingleton;
}
public Object clone() throws CloneNotSupportedException {
throw new CloneNotSupportedException();
}
}
另一個,我們的決賽,非常受歡迎的和智能的方法實現(xiàn)單例使用枚舉,而照顧我們到目前為止的所有問題。
public enum EnumSingleton{
INSTANCE;
}
有時,人們談?wù)搯渭缍鄠€jvm,讓我們觸摸谍珊。 單身意味著只有一個對象,我們非常清楚,JVM對象生命周期管理,所以一個共享對象跨多個JVM是不可能的治宣。
但是如果你需要,你可以在一個JVM中創(chuàng)建對象并分發(fā)它作為一個序列化的對象,可以使用其他JVM(但是記住,你反序列化,那么請記住,任何靜態(tài)或標(biāo)記為瞬態(tài)將無法實現(xiàn),某個地方,打破了單合同)。 你也可以嘗試使用RMI服務(wù)器對象作為單件來適應(yīng)您的需要。
學(xué)習(xí)快樂!