4). 枚举单例模式
不仅可以解决线程同步,还可以防止反序列化。枚举单例模式是《Effective Java》中推荐的
package com.bytearch.designPattern.singleton; /** * 内部枚举类单例模式 */ public class Singleton { private Singleton() { } /** * 静态枚举 */ enum SingletonEnum { INSTANCE; private Singleton singleton; SingletonEnum() { singleton = new Singleton(); } private Singleton getInstance() { return singleton; } } public static Singleton getInstance() { return SingletonEnum.INSTANCE.getInstance(); } /** * 测试 * @param args */ public static void main(String[] args) { for (int i = 0; i < 100; i++) { new Thread(()-> { System.out.println(Singleton.getInstance().hashCode()); }).start(); } } }
5). 容器式单例模式
/** * 容器式单例模式 */ public class ContainerSingleton { private ContainerSingleton() { } private static Map<String, Object> singletonObjects = new ConcurrentHashMap<>(); public static Object getBean(String className) { Object singletonObject = singletonObjects.get(className); if (singletonObject == null) { synchronized (singletonObjects) { singletonObject = singletonObjects.get(className); if (singletonObject == null) { try { try { singletonObject = Class.forName(className).newInstance(); } catch (InstantiationException e) { e.printStackTrace(); } catch (IllegalAccessException e) { e.printStackTrace(); } singletonObjects.put(className, singletonObject); } catch (ClassNotFoundException e) { e.printStackTrace(); } } } } return singletonObject; } }
spring框架中使用的就是容器式单例模式。
下面我们看看Spring源码 org/springframework/beans/factory/support/DefaultSingletonBeanRegistry.java
/** * Return the (raw) singleton object registered under the given name. * <p>Checks already instantiated singletons and also allows for an early * reference to a currently created singleton (resolving a circular reference). * @param beanName the name of the bean to look for * @param allowEarlyReference whether early references should be created or not * @return the registered singleton object, or {@code null} if none found */ protected Object getSingleton(String beanName, boolean allowEarlyReference) { Object singletonObject = this.singletonObjects.get(beanName); if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) { synchronized (this.singletonObjects) { singletonObject = this.earlySingletonObjects.get(beanName); if (singletonObject == null && allowEarlyReference) { ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName); if (singletonFactory != null) { singletonObject = singletonFactory.getObject(); this.earlySingletonObjects.put(beanName, singletonObject); this.singletonFactories.remove(beanName); } } } } return (singletonObject != NULL_OBJECT ? singletonObject : null); }
4.总结
- ·单例模式有很多"变种",以上是总结的几种比较好的实现(也都是线程安全的),有小伙伴就疑问了,这么多该使用哪一种呢? 其实都可以使用,可以看自己爱好,可能工作上用得比较多的是第一种"饿汉式",个人比较推荐"静态内部类-单例模式",
- ·以上大家很容易 发现 "容器式单例模式 " 也是 "懒汉模式-双重验证" 的变种,实际场景上我们完全可以根据需要适当定制,做到活学活用。
例如我在轻量级socket连接池实现中也使用了“容器式单例模式”。
public class ConnectionPool { /** * key is ip:port, value is ConnectionManager */ private final static ConcurrentHashMap<String, ConnectionManager> CP = new ConcurrentHashMap<String, ConnectionManager>(); public static Connection getConnection(InetSocketAddress socketAddress) throws MyException { if (socketAddress == null) { return null; } String key = getKey(socketAddress); ConnectionManager connectionManager; connectionManager = CP.get(key); if (connectionManager == null) { synchronized (ConnectionPool.class) { connectionManager = CP.get(key); if (connectionManager == null) { connectionManager = new ConnectionManager(socketAddress); CP.put(key, connectionManager); } } } return connectionManager.getConnection(); } }
5.支持
如果你觉得这篇内容对你挺有启发,我想请你帮二个小忙:
- 点个 [在看/转发],让更多的人也能看到这篇内容 (喜欢不点在看/转发,都是耍流氓 🙂)
- 关注公众号 [浅谈架构], 公众号后台回复以下"编号" 或 "关键字",送你全套适合你的学习资料.
101: Java初级
102: Java高级进阶
103: Java面试