《Java-單例模式》

 

單例模式確保某個類只有一個實例,並且自行實例化並向整個系統提供這個實例。在計算機系統中,線程池、緩存、日誌對象、對話框、打印機、顯卡的驅動程序對象常被設計成單例。這些應用都或多或少具備資源管理器的功能。每臺計算機能夠有若干個打印機,但只能有一個Printer Spooler,以免兩個打印做業同時輸出到打印機中。每臺計算機能夠有若干通訊端口,系統應當集中管理這些通訊端口,以免一個通訊端口同時被兩個請求同時調用。總之,選擇單例模式就是爲了不不一致狀態,避免政出多頭。java

那就讓咱們看看幾種常見的單例模式吧。緩存

//懶漢式單例類.在第一次調用的時候實例化本身 
public class Singleton {
    private Singleton() {}
    private static Singleton single=null;
    //靜態工廠方法 
    public static Singleton getInstance() {
         if (single == null) {  
             single = new Singleton();
         }  
        return single;
    }
}

應該是你們寫的比較多的了,可是這種寫法的時候在多線程的時候就會出現問題,因而就引出了下面兩種寫法安全

一、在getInstance方法上加同步多線程

public static synchronized Singleton getInstance() {
         if (single == null) {  
             single = new Singleton();
         }  
        return single;
}

二、雙重檢查鎖定ide

public static Singleton getInstance() {
        if (singleton == null) {  
            synchronized (Singleton.class) {  
               if (singleton == null) {  
                  singleton = new Singleton(); 
               }  
            }  
        }  
        return singleton; 
    }

可是上面這兩種加了同步鎖的單例在效率方便又不是很高,因而又有改進的方式了性能

public class Singleton {  
    private static class LazyHolder {  
       private static final Singleton INSTANCE = new Singleton();  
    }  
    private Singleton (){}  
    public static final Singleton getInstance() {  
       return LazyHolder.INSTANCE;  
    }  
}

這種靜態內部類實現的單例,既實現了線程安全,又避免了同步帶來的性能影響。線程

其實還有不少種單例模式,咱們再往下面看看設計

//餓漢式單例類.在類初始化時,已經自行實例化 
public class Singleton1 {
    private Singleton1() {}
    private static final Singleton1 single = new Singleton1();
    //靜態工廠方法 
    public static Singleton1 getInstance() {
        return single;
    }
}

這個就是所謂的餓漢式單例,在類建立的同時就已經建立好一個靜態的對象供系統使用,之後再也不改變,因此天生是線程安全的。日誌

彆着急還有兩種也是我才見到的code

一、枚舉單例

public enum Singleton {
    INSTANCE {

        @Override
        protected void read() {
            System.out.println("read");
        }

        @Override
        protected void write() {
            System.out.println("write");
        }

    };
    protected abstract void read();
    protected abstract void write();
}

枚舉單例很簡單就作到了1.線程安全 2.不會由於序列化而產生新實例 3.防止反射攻擊

二、利用AtomicReference來實現

public class Singleton {
    private static final AtomicReference<Singleton> INSTANCE = new AtomicReference<>();
    private Singleton (){}
    public static  Singleton getInstance() {
        for (;;) {
            Singleton current = INSTANCE.get();
            if (current != null) {
                return current;
            }
            current = new Singleton();
            if (INSTANCE.compareAndSet(null, current)) {
                return current;
           }
     }
  }
}

看到這個我都蒙圈了。

具體怎麼取選擇單例模式的實現就看你們本身了

相關文章
相關標籤/搜索