應用單例模式時,類只能有一個對象實例,這麼做的目的是避免不一致狀態。
餓漢式單例:(立即加載)
// 餓漢式單例
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();
}
}
引用《徹頭徹尾理解單例模式與多線程》