1. 程式人生 > 其它 >註冊式單例--容器法

註冊式單例--容器法

技術標籤:設計模式Java多執行緒ioc設計模式java

通過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方法還是沒能保證執行緒安全,故還需要加鎖