設計模式-單例模式及多種實現
阿新 • • 發佈:2019-07-09
單例模式
單例模式(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();