單例的實現
單例設計模式的問題
1. 線程安全問題用synchronized修飾實例化部分代碼
2. 性能問題–采用懶漢式實例化
3. 指令重排序問題–用volatile修飾實例
4. 反序列化攻擊問題–構造函數判斷存在實例時拋異常
5. 反射攻擊問題–增加readResolve方法
6. 不符合開閉原則,需要改代碼
五種單例實現方式
1. 餓漢式
package me.muphy.singleton; import java.io.Serializable; /** * 2019/4/1 * 莫非 */ public class HungrySingleton implements Serializable{ private static final HungrySingleton hungrySingleton = new HungrySingleton(); private HungrySingleton() { } public static HungrySingleton getInstance() { return hungrySingleton; } private ObjectreadResolve() { return hungrySingleton; } }
2. 懶漢式延時加載方式
package me.muphy.singleton; /** * 2019/4/1 * 莫非 */ public class LazySingleton { private volatile static LazySingleton lazySingleton = null; private LazySingleton() { if (lazySingleton != null) { throw new RuntimeException("此類以單例存在!"); } } public static LazySingleton getInstance() throws Exception { if (lazySingleton == null) { synchronized (LazySingleton.class) { if (lazySingleton == null) { lazySingleton = new LazySingleton(); } } } return lazySingleton; } private Object readResolve() { return lazySingleton; } }
3. 懶漢式 內部內實現單例
package me.muphy.singleton; /** * 2019/4/1 * 莫非 */ public class LazyJvmSingleton { private LazyJvmSingleton(){ } public static LazyJvmSingleton getInstance(){ return LazySingleton.lazyJvmSingleton; } private static class LazySingleton{ public static final LazyJvmSingleton lazyJvmSingleton = new LazyJvmSingleton(); } private Object readResolve(){ return LazySingleton.lazyJvmSingleton; } }
4. 注冊式 枚舉式單例
package me.muphy.singleton; /** * 2019/4/1 * 莫非 */ public enum EnumSingleton { INSTANCE; private Object data; public Object getData() { return data; } public void setData(Object data) { this.data = data; } public static EnumSingleton getInstance() { return INSTANCE; } }
5. 注冊式 容器式單例
package me.muphy.singleton; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; /** * 2019/4/1 * 莫非 */ 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)) { try { Object obj = Class.forName(className).newInstance(); ioc.put(className, obj); return obj; } catch (ClassNotFoundException e) { e.printStackTrace(); } catch (IllegalAccessException e) { e.printStackTrace(); } catch (InstantiationException e) { e.printStackTrace(); } } } return ioc.get(className); } }
線程內部的單例
線程內部的單例采用注冊式單例,是偽線程安全的,可用來實現多數據源切換
package me.muphy.singleton; /** * 2019/4/2 * 莫非 */ public class ThreadLocalSingleton { private ThreadLocalSingleton() { } private static final ThreadLocal<ThreadLocalSingleton> threadLocalInstance = new ThreadLocal<ThreadLocalSingleton>() { @Override protected ThreadLocalSingleton initialValue() { return new ThreadLocalSingleton(); } }; public static ThreadLocalSingleton getInstance() { return threadLocalInstance.get(); } }
