JAVA理解單例模式
單例模式,英文名為:Singleton pattern。首先,我們先去理解字面意思。Singleton:一個,獨身。pattern:模式,圖案,樣品。在字面上,可以理解為“一個樣品”。哈哈。再來看看特點:
- 只能有一個例項
- 必須自己建立自己唯一例項
- 必須給所有其他的物件提供這一例項
看到了這些特點,你在想,那麼有了這些特點有什麼作用、又有什麼好處呢?很好,對待這些不明白、沒見過的知識點抱有種種疑問是非常好的節奏。
單例模式的作用簡單點理解是為了避免不一致狀態,避免政出多頭。單例模式為一個面向物件的應用程式提供了物件惟一的訪問點,不管它實現何種功能,整個應用程式都會同享一個例項物件。
在計算機系統中,執行緒池、快取、日誌物件、對話方塊、印表機、顯示卡的驅動程式物件常被設計成單例。這些應用都或多或少具有資源管理器的功能。每臺計算機可以有若干個印表機,但只能有一個Printer Spooler,以避免兩個列印作業同時輸出到印表機中。每臺計算機可以有若干通訊埠,系統應當集中管理這些通訊埠,以避免一個通訊埠同時被兩個請求同時呼叫。
下面通過程式碼來了解下單例模式中的懶漢式和餓漢式。
懶漢式一:
public class Singleton
{
//私有的預設構造子
private Singleton()
{
}
//注意,這裡沒有final
private static Singleton single=null;
//靜態工廠方法
public synchronized static Singleton getInstance()
{
if(single==null)
{
single=new Singleton();
}
return single;
}
}
懶漢式二:
public class Singleton
{
private Singleton mInstance = null;
private Singleton()
{
}
public static Singleton getInstance()
{
if (mInstance == null)
{
synchronized (Singleton.class)
{
if (mInstance == null )
{
mInstance = new Singleton();
}
}
}
return mInstance;
}
}
在“懶漢式一”中,將例項的構造方法私有化,使外部類不能通過new來構造出Singleton物件,只能通過Singleton類中提供的getInstance()方法來得到Singleton物件。當有多個執行緒呼叫getInstance()方法時,因為在方法呼叫上加了同步,所以雖然執行緒安全了,但是每次都要同步,會影響效能,畢竟大多的情況下是不需要同步的。
在“懶漢式二”中,在getInstance()方法中做了兩次null檢查,確保了只有第一次呼叫單例的時候才會做同步,這樣也是執行緒安全的,同時避免了每次都同步的效能損耗。
餓漢式:
public class Singleton
{
private Singleton mInstance = new Singleton;
private Singleton()
{
}
public static Singleton getInstance()
{
return mInstance;
}
}
“餓漢式”在類建立的同時就已經建立好一個靜態的物件供系統使用,以後不再改變,所以天生是執行緒安全的。
餓漢式在類建立的同時就例項化一個靜態物件出來,不管之後會不會使用這個單例,都會佔據一定的記憶體,但是相應的,在第一次呼叫時速度也會更快,因為其資源已經初始化完成。
而懶漢式顧名思義,會延遲載入,在第一次使用該單例的時候才會例項化物件出來,第一次呼叫時要做初始化,如果要做的工作比較多,效能上會有些延遲,之後就和餓漢式一樣了。
什麼是執行緒安全?
如果你的程式碼所在的程序中有多個執行緒在同時執行,而這些執行緒可能會同時執行這段程式碼。如果每次執行結果和單執行緒執行的結果是一樣的,而且其他的變數的值也和預期的是一樣的,就是執行緒安全的。
或者說:一個類或者程式所提供的介面對於執行緒來說是原子操作,或者多個執行緒之間的切換不會導致該介面的執行結果存在二義性,也就是說我們不用考慮同步的問題,那就是執行緒安全的。
若每個執行緒中對全域性變數、靜態變數只有讀操作,而無寫操作,一般來說,這個全域性變數是執行緒安全的;若有多個執行緒同時執行寫操作,一般都需要考慮執行緒同步,否則的話就可能影響執行緒安全。
上述內容若有錯誤,望指出。