單例模式是設計模式中相對簡單的,只有一個單例類,沒有其他的層次結構與抽象。該模式需要確保該類只能生成一個對象,通常是該類需要消耗太多的資源或者沒有沒有多個實例的理由。程序員在Java模式設計的時候應該如何更好地使用單例模式呢?本文動力節點的老師就為大家詳解一下單例模式,希望對大家有用。
為何需要單例模式
對于系統中的某些類來說,只有一個實例很重要,例如,一個系統只能有一個窗口管理器或文件系統;一個系統只能有一個計時工具或ID(序號)生成器。
單例模式設計要點
保證該類只有一個實例。將該類的構造方法定義為私有方法,這樣其他處的代碼就無法通過調用該類的構造方法來實例化該類的對象,提供一個該實例的訪問點。一般由該類自己負責創建實例,并提供一個靜態方法作為該實例的訪問點。
餓漢 vs. 懶漢
餓漢 聲明實例引用時即實例化
懶漢 靜態方法第一次被調用前不實例化,也即懶加載。對于創建實例代價大,且不定會使用時,使用懶加載模式可以減少開銷。
實現單例模式的九種方法
線程不安全的懶漢 - 多線程不可用
package com.jasongj.singleton1;
public class Singleton {
private static Singleton INSTANCE;
private Singleton() {};
public static Singleton getInstance() {
if (INSTANCE == null) {
INSTANCE = new Singleton();
}
return INSTANCE;
}
}
優點:達到了Lazy Loading的效果
缺點:只有在單線程下能保證只有一個實例,多線程下有創建多個實例的風險
同步方法下的懶漢 - 可用,不推薦
package com.jasongj.singleton2;
public class Singleton {
private static Singleton INSTANCE;
private Singleton() {};
public static synchronized Singleton getInstance() {
if (INSTANCE == null) {
INSTANCE = new Singleton();
}
return INSTANCE;
}
}
優點:線程安全,可確保正常使用下(不考慮通過反射調用私有構造方法)只有一個實例
缺點:每次獲取實例都需要申請鎖,開銷大,效率低
同步代碼塊下的懶漢 - 不可用
package com.jasongj.singleton3;
public class Singleton {
private static Singleton INSTANCE;
private Singleton() {};
public static Singleton getInstance() {
if (INSTANCE == null) {
synchronized (Singleton.class) {
INSTANCE = new Singleton();
}
}
return INSTANCE;
}
}
優點:不需要在每次調用時加鎖,效率比上一個高
缺點:雖然使用了synchronized,但本質上是線程不安全的。
不正確雙重檢查(Double Check)下的懶漢 - 不推薦
package com.jasongj.singleton4;
public class Singleton {
private static Singleton INSTANCE;
private Singleton() {};
public static Singleton getInstance() {
if (INSTANCE == null) {
synchronized(Singleton.class){
if(INSTANCE == null) {
INSTANCE = new Singleton();
}
}
}
return INSTANCE;
}
}
優點:使用了雙重檢查,很大程度上避免了線程不安全,同時也避免了不必要的鎖開銷
缺點:依然存在創建多個實例的可能。因為每個線程都有自己的一份拷貝,并不能保證實例化后將INSTANCE的引用拷回主內存,不能保證對其它線程立即可見,所以仍然有可能造成多個實例被創建
正確雙重檢查(Double Check)下的懶漢 - 推薦
package com.jasongj.singleton5;
public class Singleton {
private static volatile Singleton INSTANCE;
private Singleton() {};
public static Singleton getInstance() {
if (INSTANCE == null) {
synchronized (Singleton.class) {
if (INSTANCE == null) {
INSTANCE = new Singleton();
}
}
}
return INSTANCE;
}
}
優點:使用了雙重檢查,同時使用volatile修飾INSTANCE,避免由于多線性同步和可見性問題造成的多實例
缺點:NA
靜態常量 餓漢 - 推薦
package com.jasongj.singleton6;
public class Singleton {
private static final Singleton INSTANCE = new Singleton();
private Singleton() {};
public static Singleton getInstance() {
return INSTANCE;
}
}
優點:實現簡單,無線程同步問題
缺點:在類裝載時完成實例化。若該實例一直未被使用,則會造成資源浪費
靜態代碼塊 餓漢 可用
package com.jasongj.singleton7;
public class Singleton {
private static Singleton INSTANCE;
static{
INSTANCE = new Singleton();
}
private Singleton() {};
public static Singleton getInstance() {
return INSTANCE;
}
}
優點:無線程同步問題
缺點:類裝載時創建實例,無Lazy Loading。實例一直未被使用時,會浪費資源
靜態內部類 推薦
package com.jasongj.singleton8;
public class Singleton {
private Singleton() {};
public static Singleton getInstance() {
return InnerClass.INSTANCE;
}
private static class InnerClass {
private static final Singleton INSTANCE = new Singleton();
}
}
優點:無線程同步問題,實現了懶加載(Lazy Loading)。因為只有調用getInstance時才會裝載內部類,才會創建實例
缺點:NA
枚舉 不推薦
package com.jasongj.singleton9;
public enum Singleton {
INSTANCE;
public void whatSoEverMethod() { }
}
優點:無線程同步問題,且能防止通過反射創建新的對象
缺點:使用的是枚舉,而非類。同時單一實例的訪問點也不是一般單例模式的靜態方法
以上就是動力節點的Java講師為大家介紹的Java單例模式的使用方法和推薦實現單例模式的九種方法,相信能對你的學習有啟發。