定義:
一個類模板,在整個系統運行過程中,只允許產生一個實例(配置文件。工廠本身,日曆)
**作用:**解決一個併發訪問線程安全問題
初衷爲了是資源共享。只需賦值一次或初始化一次,大家都能重複利用
應用場景: 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;
}
}