單例模式

定義:
一個類模板,在整個系統運行過程中,只允許產生一個實例(配置文件。工廠本身,日曆)
**作用:**解決一個併發訪問線程安全問題

初衷爲了是資源共享。只需賦值一次或初始化一次,大家都能重複利用

應用場景: Listener監聽器,日曆IOC容器,配置信息Config

技術方案: 保證整個運行過程只有一個

**解決問題:**惡劣環境(程序健壯性)

保障單例技術方案:

餓漢式,懶漢式,註冊登記式(枚舉式),反序列如何保證單例

餓漢式:

實例使用前實例化,避免了線程安全問題
**優點:**沒有任何鎖,執行效率高,用戶體驗比懶漢好,
**缺點:**類加載就初始化,不管是不是用都佔用空間,可能浪費內存

懶漢式:

默認時不用,使用時new(延時加載)
外部類被調用的時候纔會加載內部類

package lazy;
/*單例
特點:內部類只有在外部類調用時纔會被加載
內部類一定是要在方法調用之前初始化
巧妙避免線程安全問題

* 兼顧了餓漢式內存浪費,也兼顧了synchronized性能問題
* 完美屏蔽了兩個缺點
* 最完美單例方式
*
* 巧妙利用了內部類
* */
public class LazyThree {
//防止反射侵入
        private static boolean inintial =false;
        //默認使用LazyThree時,會先初始化內部類,如果沒使用內部類,內部類不會加載
        private LazyThree() {
            synchronized (LazyThree.class){
                if(inintial==false){
                    inintial=!inintial;
                }else {
                    throw new RuntimeException("單例已被侵犯");
                }
            }
        }
//防止反射侵入        
    
        /*static爲了使單例空間共享
        final保證方法不會被重寫重載*/
        public static final LazyThree getInstance(){
            /*if (lazyThree ==null){
                LazyThree lazyThree =new LazyThree();
            }
            return lazyThree;*/
            return LazyHolder.LAZY;
        }
        //靜態內部類
        public static class LazyHolder{
            private static final LazyThree LAZY=new LazyThree();
        }
    
    }

註冊登記式:

每使用一次都往一個固定容器中註冊並將使用過的對象進行緩存,下次去對象直接從緩存中取出,以保證每次獲取都是同一個對象,(枚舉式、IOC單例模式是典型註冊登記模式)

package register;

import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

public class BeanFactory {
    private BeanFactory() {
    }
    private static Map<String,Object> ioc=new ConcurrentHashMap<>();
    public static synchronized Object getBean(String className){
        //控制線程安全
        if(!ioc.containsKey(className)){
            Object obj=null;
            try {
                obj=Class.forName(className).newInstance();
                ioc.put(className,obj);
            } catch (Exception e) {
                e.printStackTrace();
            }
            return obj;

        }else {
            return ioc.get(className);
        }
    }
}

序列化與反序列化保證單例問題解決方案:重寫readResolve()

  package seriable;

import java.io.Serializable;

public class Seriable implements Serializable {
    //序列化就是把內存中的狀態通過轉換,變成字節碼形式
    //從而轉換一個IO留,寫入到其他地方,可以是磁盤網絡IO流
    //內存中狀態就被永久保存下來了(整個過程叫持久化)
//反序列化 ,將已經持久化的字節碼內容轉換爲IO流
//進而通過IO流的讀取,將讀取的內容轉化成JAVA對象,
//轉換過程中會重新new對象
private Seriable() {
}
public static final Seriable INSTANCE=new Seriable();
public  static Seriable getInstance(){
    return INSTANCE;
}
//重寫readResolve轉換過程中不會重新new對象,保證單例
private Object readResolve(){
    return INSTANCE;
}

}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章