註冊式單例--容器法
阿新 • • 發佈:2021-01-19
通過map來模仿spring中的容器
public class ContainerSingleton {
/**
* 構造方法私有化
*/
private ContainerSingleton(){}
/**
* 容器:用來儲存物件
*/
private static Map<String,Object> ioc = new ConcurrentHashMap<String, Object>();
/**
* 獲取對應的bean
* @param className
* @return
*/
public static 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;
}
return ioc.get(className);
}
}
此方法執行緒不安全,會出現併發問題
public static void main(String[] args) {
for (int i = 0; i < 6; i++) {
new Thread(()->{
Object obj = ContainerSingleton.getBean("com.gupao.vip.partten.singleton.register.MyPojo");
System.out.println(System.currentTimeMillis()+""+obj);
}).start();
}
}
結果:由於併發,出現了三個例項
嘗試加鎖
public class ContainerSingleton {
/**
* 構造方法私有化
*/
private ContainerSingleton(){}
/**
* 容器:用來儲存物件
*/
private static Map<String,Object> ioc = new ConcurrentHashMap<String, Object>();
/**
* 獲取對應的bean
* @param className
* @return
*/
public static Object getBean(String className){
synchronized (ioc){
if (!ioc.containsKey(className)){//如果容器中沒有
Object obj = null;
try {
//通過反射獲取到這個類,並例項化--簡易工廠
obj = Class.forName(className).newInstance();
ioc.put(className,obj);
} catch (Exception e) {
e.printStackTrace();
}
return obj;
}
return ioc.get(className);
}
}
}
結果:加鎖後例項變成了同一個,但降低了效能
優點:物件方便管理,其實也屬於懶載入,只是存線上程安全問題。這裡的ConcurrentHashMap只能保證map內部是安全的(put是安全的),但這裡的getBean方法還是沒能保證執行緒安全,故還需要加鎖