目錄
什么叫做單例模式?
餓漢式和懶漢式的區別?
餓漢式-方式1(靜態變量方式)
餓漢式-方式2(靜態代碼塊方式)
懶漢式-方式1(線程不安全)
懶漢式-方式2(線程安全)
懶漢式-方式3(雙重檢查鎖)
懶漢式-方式4(靜態內部類方式)
什么叫做單例模式?
????????涉及到一個單一的類,該類負責創建自己的對象,同時確保只有單個對象被創建。這個類提供 了一種訪問其唯一的對象的方式,可以直接訪問,不需要實例化該類的對象。
餓漢式和懶漢式的區別?
? ? ? ? 餓漢式:類加載就會導致該單實例對象被創建
? ? ? ? 懶漢式:類加載不會導致該單實例對象被創建,而是首次使用該對象時才會創建
? ? ? ? 導致類加載的情況:new 對象,創建子類,調用靜態屬性
? ? ? ? 類加載是什么意思:就是把你的變量和方法存在內存當中
? ? ? ? 代碼區別如下:
? ? ? ? 人話來說就是創建對象的時機不一樣,如果看不懂的話建議去補java基礎靜態這一塊的知識
//餓漢式
public class Singleton {private Singleton(){}
// 提前創建好單列對象;private static Singleton instance = new Singleton();public static Singleton getInstance(){return instance;}}
//測試代碼:
public class Test {public static void main (String[] args) {//因為這里調用的是靜態方法,所以導致類加載,就會執行 new Singleton();從而創建對象//導致類加載的情況:new 對象,創建子類,調用靜態屬性Singleton instance = Singleton.getInstance();Singleton instance1 = Singleton.getInstance();System.out.println(instance==instance1);}
}
============================================================================
//餓漢式
public class Singleton {private Singleton(){}private static Singleton instance;public static Singleton getInstance(){if (instance==null){//調用的時候才創建對象//判短對象為空才創建對象instance=new Singleton();}return instance;}
}
public class Test {public static void main (String[] args) {//調用方法的時候才創建對象Singleton instance = Singleton.getInstance();Singleton instance1 = Singleton.getInstance();System.out.println(instance==instance1);}
}
餓漢式-方式1(靜態變量方式)
?
/**
* 餓漢式
* 靜態變量創建類的對象
*/
public class Singleton {
//私有構造方法
private Singleton() {}
//在成員位置創建該類的對象
private static Singleton instance = new Singleton();
//對外提供靜態方法獲取該對象
public static Singleton getInstance() {
return instance;
}
}
缺點:
該方式在成員位置聲明Singleton類型的靜態變量,并創建Singleton類的對象instance。 instance對象是隨著類的加載而創建的。如果該對象足夠大的話,而一直沒有使用就會造成內存 的浪費。
餓漢式-方式2(靜態代碼塊方式)
?
/**
* 惡漢式
* 在靜態代碼塊中創建該類對象
*/
public class Singleton {
//私有構造方法
private Singleton() {}
//在成員位置創建該類的對象
private static Singleton instance;
static {
instance = new Singleton();
}
//對外提供靜態方法獲取該對象
public static Singleton getInstance() {
return instance;
}
}
缺點:
該方式在成員位置聲明Singleton類型的靜態變量,而對象的創建是在靜態代碼塊中,也是對著 類的加載而創建。所以和餓漢式的方式1基本上一樣,當然該方式也存在內存浪費問題。
懶漢式-方式1(線程不安全)
/**
* 懶漢式
* 線程不安全
*/
public class Singleton {
//私有構造方法
private Singleton() {}
//在成員位置創建該類的對象
private static Singleton instance;
//對外提供靜態方法獲取該對象
public static Singleton getInstance() {
if(instance == null) {
instance = new Singleton();
}
return instance;
}
}
缺點:
從上面代碼我們可以看出該方式在成員位置聲明Singleton類型的靜態變量,并沒有進行對象的 賦值操作,那么什么時候賦值的呢?當調用getInstance()方法獲取Singleton類的對象的時 候才創建Singleton類的對象,這樣就實現了懶加載的效果。但是,如果是多線程環境,會出現 線程安全問題。
懶漢式-方式2(線程安全)
?
/**
* 懶漢式
* 線程安全
*/
public class Singleton {
//私有構造方法
private Singleton() {}
//在成員位置創建該類的對象
private static Singleton instance;
//對外提供靜態方法獲取該對象
public static synchronized Singleton getInstance() {
if(instance == null) {
instance = new Singleton();
}
return instance;
}
}
缺點:
該方式也實現了懶加載效果,同時又解決了線程安全問題。但是在getInstance()方法上添加了 synchronized關鍵字,導致該方法的執行效果特別低。從上面代碼我們可以看出,其實就是在 初始化instance的時候才會出現線程安全問題,一旦初始化完成就不存在了。
就是每個現場都會拿到鎖,導致效率降低,應該是當沒有獲取對象的誰時候拿到鎖。
?
懶漢式-方式3(雙重檢查鎖)
?
public class Singleton {private Singleton(){}//聲明一個Singleton類型的變量private static Singleton instance;public static Singleton getInstance(){if (instance==null){//為空的時候才會拿到鎖synchronized (Singleton.class){if (instance==null){instance=new Singleton();}}}return instance;}
}
雙重檢查鎖模式是一種非常好的單例實現模式,解決了單例、性能、線程安全問題,上面的雙重檢 測鎖模式看上去完美無缺,其實是存在問題,在多線程的情況下,可能會出現空指針問題,出現問 題的原因是JVM在實例化對象的時候會進行優化和指令重排序操作。 要解決雙重檢查鎖模式帶來空指針異常的問題,只需要使用 volatile 關鍵字, volatile 關 鍵字可以保證可見性和有序性。
?
懶漢式-方式4(靜態內部類方式)
?
public class Singleton {
//私有構造方法
private Singleton() {}
private static class SingletonHolder {
private static final Singleton INSTANCE = new Singleton();
}
//對外提供靜態方法獲取該對象
public static Singleton getInstance() {
return SingletonHolder.INSTANCE;
}
}
?第一次加載Singleton類時不會去初始化INSTANCE,只有第一次調用getInstance,虛擬機加 載SingletonHolder 并初始化INSTANCE,這樣不僅能確保線程安全,也能保證 Singleton 類的唯一性。 小結: 靜態內部類單例模式是一種優秀的單例模式,是開源項目中比較常用的一種單例模式。在沒有加任 何鎖的情況下,保證了多線程下的安全,并且沒有任何性能影響和空間的浪費。