單列設計模式

IT路上的小白發表於2021-01-11

單列中的四種實現方式

方式一:普通的餓漢式和懶漢式單例模式

三部曲:

(1)私有化構造方法
(2)私有化靜態本類物件作為屬性
(3)提供公有靜態方法獲取本類物件

 1.普通的餓漢式(靜態的內部)

public class Client {
    public static void main(String[] args) {
        Singleton.getInstance();
    }

    static class Singleton {
        private static final Singleton instance = new Singleton();

        private Singleton(){}

        public static Singleton getInstance(){
            return  instance;
        }

    }
}

2.餓漢式靜態程式碼塊單例模式

//餓漢式靜態程式碼塊單例模式
public class HungryStaticSingleton {
    private static final HungryStaticSingleton instance;

    static {
        instance = new HungryStaticSingleton();
    }

    private HungryStaticSingleton(){}

    public static HungryStaticSingleton getInstance(){
        return  instance;
    }
}

3.餓漢式靜態程式碼塊單例模式

/**
 * 優點:執行效率高,效能高,沒有任何的鎖
 * 缺點:某些情況下,可能會造成記憶體浪費
 */
//餓漢式靜態程式碼塊單例模式
public class HungrySingleton {

    private static final HungrySingleton instance = new HungrySingleton();

    private HungrySingleton(){}

    public static HungrySingleton getInstance(){
        return  instance;
    }
}

二:懶漢式

1.懶漢式單例模式在外部需要使用的時候才進行例項化,這種是執行緒不安全的,如果多個執行緒同時併發訪問,假設多個執行緒同時都進入到了 if(instance == null){}條件判斷裡面,那麼就會同時建立多個物件。

/**
 * 優點:節省了記憶體,執行緒安全
 * 缺點:效能低
 */
//懶漢式單例模式在外部需要使用的時候才進行例項化
public class LazySimpleSingletion {
    //靜態塊,公共記憶體區域
    private static LazySimpleSingletion instance;

    private LazySimpleSingletion(){}

    public synchronized static LazySimpleSingletion getInstance(){
        if(instance == null){
            instance = new LazySimpleSingletion();
        }
        return instance;
    }
}

2.單次檢查機制(使用類鎖),這種也是有缺點的,使用的 synchronized 關鍵字,嚴重的影響了效能.

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

3.利用雙重檢查機制(DCL) ,保證了執行緒的安全

/**
 * 優點:效能高了,執行緒安全了
 * 缺點:可讀性難度加大,不夠優雅
 */
public class LazyDoubleCheckSingleton {
    private volatile static LazyDoubleCheckSingleton instance;
    private LazyDoubleCheckSingleton(){}

    public static LazyDoubleCheckSingleton getInstance(){
        //檢查是否要阻塞
        if (instance == null) {
            synchronized (LazyDoubleCheckSingleton.class) {
                //檢查是否要重新建立例項
                if (instance == null) {
                    instance = new LazyDoubleCheckSingleton();
                    //指令重排序的問題
                }
            }
        }
        return instance;
    }
}

4.自認為史上最牛的單例模式的實現方式 (這裡有個技術上的高深的點技術基礎點,說到底還是技術的基礎和本質)----->>>> 利用了Java本身語法特點,內部類預設不載入

/*
  ClassPath : LazyStaticInnerClassSingleton.class
              LazyStaticInnerClassSingleton$LazyHolder.class
   優點:寫法優雅,利用了Java本身語法特點,效能高,避免了記憶體浪費,不能被反射破壞
   缺點:不優雅
 */
//這種形式兼顧餓漢式單例模式的記憶體浪費問題和synchronized的效能問題
//完美地遮蔽了這兩個缺點
//自認為史上最牛的單例模式的實現方式
public class LazyStaticInnerClassSingleton {
    //使用LazyInnerClassGeneral的時候,預設會先初始化內部類
    //如果沒使用,則內部類是不載入的
    private LazyStaticInnerClassSingleton(){
        if(LazyHolder.INSTANCE != null){
            throw new RuntimeException("不允許建立多個例項");
        }
    }
    //每一個關鍵字都不是多餘的,static是為了使單例的空間共享,保證這個方法不會被重寫、過載
    private static LazyStaticInnerClassSingleton getInstance(){
        //在返回結果以前,一定會先載入內部類
        return LazyHolder.INSTANCE;
    }

    //利用了Java本身語法特點,內部類預設不載入
    private static class LazyHolder{
        private static final LazyStaticInnerClassSingleton INSTANCE = new LazyStaticInnerClassSingleton();
    }

}

5.列舉法

public enum EnumSingleton {
    INSTANCE;

    private Object data;

    public Object getData() {
        return data;
    }

    public void setData(Object data) {
        this.data = data;
    }

    public static EnumSingleton getInstance(){return INSTANCE;}
}

 6.序列化一個單列物件

import java.io.Serializable;

public class SeriableSingleton implements Serializable {


    //序列化
    //把記憶體中物件的狀態轉換為位元組碼的形式
    //把位元組碼通過IO輸出流,寫到磁碟上
    //永久儲存下來,持久化

    //反序列化
    //將持久化的位元組碼內容,通過IO輸入流讀到記憶體中來
    //轉化成一個Java物件


    public  final static SeriableSingleton INSTANCE = new SeriableSingleton();
    private SeriableSingleton(){}

    public static SeriableSingleton getInstance(){
        return INSTANCE;
    }

    private Object readResolve(){ return INSTANCE;}

}

 

7.手動建立一個單列物件(根據類名來建立)

public class ContainerSingleton {

    private ContainerSingleton(){}

    private static Map<String,Object> ioc = new ConcurrentHashMap<String, Object>();

    public static Object getInstance(String className){
        Object instance = null;
        if(!ioc.containsKey(className)){
            try {
                instance = Class.forName(className).newInstance();
                ioc.put(className, instance);
            }catch (Exception e){
                e.printStackTrace();
            }
            return instance;
        }else{
            return ioc.get(className);
        }
    }
}

8.ThreadLocal設定單列

public class ThreadLocalSingleton {
    private static final ThreadLocal<ThreadLocalSingleton> threadLocaLInstance =
            new ThreadLocal<ThreadLocalSingleton>(){
                @Override
                protected ThreadLocalSingleton initialValue() {
                    return new ThreadLocalSingleton();
                }
            };

    private ThreadLocalSingleton(){}

    public static ThreadLocalSingleton getInstance(){
        return threadLocaLInstance.get();
    }
}

 

相關文章