今天學習了單例模式,網上有一些講解,真心不錯,我在這裏歸納總結一下。
首先來說明一下什麼是單例模式,所謂單例模式,就體現在了這個“單”上,也就是說,在同一個JVM中,保證該類只有一個實例對象,這種模式在框架中用的很多,比如數據庫連接的時候,就大量使用了這個模式。
在來說說什麼時候使用,具體什麼時候使用,我覺得還要具體結合需求來定,一般而言,大量相似的重複操作,就沒必要每次都new一個對象出來,那樣不但浪費資源而且也不便於管理。比如我們做桌面程序的時候,要調出菜單,我們沒必要每次點擊都要new一個菜單,而是先判斷一下這個菜單有沒有被實例化,如果已經被實例化了,就直接返回,如果沒有被實例化,在去實例化也不遲。
下邊我來舉例說明一下如何實現單例模式
(以下代碼不是我自己寫的,是在網上看到寫的不錯了,與大家分享一下)
首先,單例模式在大體上可以分爲懶漢式,餓漢式
1、懶漢式,就是在第一次被人調用的時候去實例化自己,實現的方法是將構造方法私有化,然後提供一個public方法作爲實例對象的統一入口,在實例化之前先做判斷,如果已經實例化了,那麼直接返回即可,否則就新建一個對象。
注意:這種方式不是線程安全的
//懶漢式單例類.在第一次調用的時候實例化自己
public class Singleton {
private Singleton() {}
private static Singleton single=null;
//靜態工廠方法
public static Singleton getInstance() {
if (single == null) {
single = new Singleton();
}
return single;
}
}
針對懶漢式,有三種解決辦法去解決線程安全問題(針對上邊的例子改進)
(1)在實例化入口增加synchronized關鍵字
public static synchronized Singleton getInstance() {
if (single == null) {
single = new Singleton();
}
return single;
}
(2)雙重檢查鎖定
public static Singleton getInstance() {
if (singleton == null) {
synchronized (Singleton.class) {
if (singleton == null) {
singleton = new Singleton();
}
}
}
return singleton;
}
在這裏大家會有疑問,爲什麼會判斷兩次?大家仔細看第2行和第4行,兩個判斷一樣,是不是重複的呢?答案是不是的,我們可以假設一下,現在有兩個線程AB,都需要這個類,那麼他們就會調用這個實例化方法,第一次判斷的時候,兩個線程都可以通過第一次判斷,然後由於synchronized關鍵字,會有一個線程等待,一個線程執行,假設A先執行,執行完之後,這個類已經被實例化了,那麼B再去判斷的時候,因爲已經被A實例化了,那麼B就不會通過判斷,直接返回那個已經創建好的實例了。
(3)靜態內部類
public class Singleton {
private static class LazyHolder {
private static final Singleton INSTANCE = new Singleton();
}
private Singleton (){}
public static final Singleton getInstance() {
return LazyHolder.INSTANCE;
}
}
這種方式實現了線程安全,在一定程度上也可以有很好的性能。
2、餓漢式
//餓漢式單例類.在類初始化時,已經自行實例化
public class Singleton1 {
private Singleton1() {}
private static final Singleton1 single = new Singleton1();
//靜態工廠方法
public static Singleton1 getInstance() {
return single;
}
}
這個方式不存在線程安全問題,因爲在類加載的時候就已經將類實例化了。而且由於final關鍵字的原因,這個實例不會被改變,所以種方式還是很方便的。
(以上代碼非個人原創,理解和說明爲本人所理解,在此聲明。)