單例模式(java程式碼實現)
阿新 • • 發佈:2019-02-05
應用單例模式時,類只能有一個物件例項,這麼做的目的是避免不一致狀態。
餓漢式單例:(立即載入)
// 餓漢式單例 public class Singleton1 { // 指向自己例項的私有靜態引用,主動建立 private static Singleton1 singleton1 = new Singleton1(); // 私有的構造方法 private Singleton1(){} // 以自己例項為返回值的靜態的公有方法,靜態工廠方法 public static Singleton1 getSingleton1(){ return singleton1; } }
懶漢式單例:(延遲載入)
// 懶漢式單例 public class Singleton2 { // 指向自己例項的私有靜態引用 private static Singleton2 singleton2; // 私有的構造方法 private Singleton2(){} // 以自己例項為返回值的靜態的公有方法,靜態工廠方法 public static Singleton2 getSingleton2(){ // 被動建立,在真正需要使用時才去建立 if (singleton2 == null) { singleton2 = new Singleton2(); } return singleton2; } }
多執行緒下執行緒安全的懶漢式單例(餓漢式本身是執行緒安全的):
1)、同步延遲載入 — synchronized方法
// 執行緒安全的懶漢式單例 public class Singleton2 { private static Singleton2 singleton2; private Singleton2(){} // 使用 synchronized 修飾,臨界資源的同步互斥訪問 public static synchronized Singleton2 getSingleton2(){ if (singleton2 == null) { singleton2 = new Singleton2(); } return singleton2; } }
2)、同步延遲載入 — synchronized塊
// 執行緒安全的懶漢式單例
public class Singleton2 {
private static Singleton2 singleton2;
private Singleton2(){}
public static Singleton2 getSingleton2(){
synchronized(Singleton2.class){ // 使用 synchronized 塊,臨界資源的同步互斥訪問
if (singleton2 == null) {
singleton2 = new Singleton2();
}
}
return singleton2;
}
}
3)、同步延遲載入 — 使用內部類實現延遲載入
// 執行緒安全的懶漢式單例
public class Singleton5 {
// 私有內部類,按需載入,用時載入,也就是延遲載入
private static class Holder {
private static Singleton5 singleton5 = new Singleton5();
}
private Singleton5() {
}
public static Singleton5 getSingleton5() {
return Holder.singleton5;
}
}
4)雙重檢測
// 執行緒安全的懶漢式單例
public class Singleton3 {
//使用volatile關鍵字防止重排序,因為 new Instance()是一個非原子操作,可能建立一個不完整的例項
private static volatile Singleton3 singleton3;
private Singleton3() {
}
public static Singleton3 getSingleton3() {
// Double-Check idiom
if (singleton3 == null) {
synchronized (Singleton3.class) { // 1
// 只需在第一次建立例項時才同步
if (singleton3 == null) { // 2
singleton3 = new Singleton3(); // 3
}
}
}
return singleton3;
}
}
5)ThreadLocal
public class Singleton {
// ThreadLocal 執行緒區域性變數,將單例instance執行緒私有化
private static ThreadLocal<Singleton> threadlocal = new ThreadLocal<Singleton>();
private static Singleton instance;
private Singleton() {
}
public static Singleton getInstance() {
// 第一次檢查:若執行緒第一次訪問,則進入if語句塊;否則,若執行緒已經訪問過,則直接返回ThreadLocal中的值
if (threadlocal.get() == null) {
synchronized (Singleton.class) {
if (instance == null) { // 第二次檢查:該單例是否被建立
instance = new Singleton();
}
}
threadlocal.set(instance); // 將單例放入ThreadLocal中
}
return threadlocal.get();
}
}