1. 程式人生 > >設計模式-單例模式及多種實現

設計模式-單例模式及多種實現


單例模式

單例模式(Singleton Pattern)是Java中最簡單的設計模式之一,屬於建立型,一般都用於保證唯一性的建立,這也是他最大的特點(保證全域性只有唯一的一個例項),並且提供一個全域性的訪問點。

單例有以下幾種形式

  • 餓漢式
  • 懶漢(存線上程安全問題)
  • 註冊登記式
  • 列舉式
  • 序列化(存線上程安全問題)
  • 反序列化(存線上程安全問題)
建立單例一般要做一下幾點:
  • 私有化構造器
  • 例項的建立
  • 提供靜態的對外訪問的單例引用

餓漢式:不管使用者是否使用,類載入的時候就會new一個物件出來,這樣有效的避免了執行緒的安全問題。但是它也有對應的缺點,如果餓漢式使用較多,會對資源暫用較多。因為不管用不用該類,都建立了物件。 餓漢式程式碼示例如下:

public class HungryTest {
    private HungryTest(){}
    private static final HungryTest hungryTest = new HungryTest();
    public static HungryTest getInstance(){
        return hungryTest;
    }
}
public class HungryTest2 {
    private static final HungryTest2 HUNGRY_TEST_2;
    private HungryTest2(){}
    static {
        HUNGRY_TEST_2 = new HungryTest2();
    }
    public static HungryTest2 getInstance(){
        return HUNGRY_TEST_2;
    }
}

懶漢式和餓漢式相反:預設類在載入的時候是不會進行物件建立的,一般是在使用者使用的時候進行建立。如果使用比較多的情況下,可能會有併發的情況出現,這樣就沒法保證唯一物件。解決這個問題的辦法有,直接在建立物件的方法上面新增synchronize,但是加上這個會出現新的問題那就是效能問題。

懶漢式程式碼示例如下:

//同步鎖,但是效能略低
public class LazyOne {
    private LazyOne(){}
    private LazyOne lazyOne = null;
    public synchronized LazyOne getInstatnce(){
        if (lazyOne == null) {
            lazyOne = new LazyOne();
        }
        return lazyOne;
    }
}

註冊式程式碼示例如下:

public class RegisterMap {
    private RegisterMap() {}
    private static Map<String, Object> map = new HashMap<>();
    public static RegisterMap getInstance(String name) {
        if (ObjectUtils.isEmpty(name)) {
            name = RegisterMap.class.getName();
        }
        if (ObjectUtils.isEmpty(map.get(name))) {
            map.put(name, new RegisterMap());
        }
        return (RegisterMap) map.get(name);
    }
}

註冊列舉式程式碼示例如下:

public enum EnumSingleton {
    BLACK, WIRTH;
    public void getInstance() {}
}

序列化程式碼示例如下:

public class SerializationSingleton implements Serializable {
    private SerializationSingleton(){}
    private static SerializationSingleton SERIALIZATION_SINGLETON = new SerializationSingleton();
    public static SerializationSingleton getInstance(){
        return SERIALIZATION_SINGLETON;
    }
    /**
     * 序列化與反序列化的協議,能夠保證單例執行緒安全。
     */
    private Object readResolve(){
        return SERIALIZATION_SINGLETON;
    }
}

容器式單例程式碼示例如下

public class ContainerSingleton {
    private ContainerSingleton(){}
    private static Map<String, Object> ioc = new ConcurrentHashMap<>();
    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);
        }
    }
}
public class Person {}
public class ContainerSingletonTest {
    public static void main(String[] args) {
        IntStream.range(0, 10).forEach(it -> {
            Thread thread = new Thread(() -> {
                Object instance = ContainerSingleton.getBean("com.echo.demo.designPatterns.singletonDesignPatterns.container.Person");
                System.out.println(Thread.currentThread().getName() + ":" + instance);
            });
            thread.start();