本文主要研究一下dubbo的ConcurrentHashSet

ConcurrentHashSet

dubbo-2.7.2/dubbo-common/src/main/java/org/apache/dubbo/common/utils/ConcurrentHashSet.java

public class ConcurrentHashSet<E> extends AbstractSet<E> implements Set<E>, java.io.Serializable {    private static final long serialVersionUID = -8672117787651310382L;    private static final Object PRESENT = new Object();    private final ConcurrentMap<E, Object> map;    public ConcurrentHashSet() {        map = new ConcurrentHashMap<E, Object>();    }    public ConcurrentHashSet(int initialCapacity) {        map = new ConcurrentHashMap<E, Object>(initialCapacity);    }    /**     * Returns an iterator over the elements in this set. The elements are     * returned in no particular order.     *     * @return an Iterator over the elements in this set     * @see ConcurrentModificationException     */    @Override    public Iterator<E> iterator() {        return map.keySet().iterator();    }    /**     * Returns the number of elements in this set (its cardinality).     *     * @return the number of elements in this set (its cardinality)     */    @Override    public int size() {        return map.size();    }    /**     * Returns <tt>true</tt> if this set contains no elements.     *     * @return <tt>true</tt> if this set contains no elements     */    @Override    public boolean isEmpty() {        return map.isEmpty();    }    /**     * Returns <tt>true</tt> if this set contains the specified element. More     * formally, returns <tt>true</tt> if and only if this set contains an     * element <tt>e</tt> such that     * <tt>(o==null&nbsp;?&nbsp;e==null&nbsp;:&nbsp;o.equals(e))</tt>.     *     * @param o element whose presence in this set is to be tested     * @return <tt>true</tt> if this set contains the specified element     */    @Override    public boolean contains(Object o) {        return map.containsKey(o);    }    /**     * Adds the specified element to this set if it is not already present. More     * formally, adds the specified element <tt>e</tt> to this set if this set     * contains no element <tt>e2</tt> such that     * <tt>(e==null&nbsp;?&nbsp;e2==null&nbsp;:&nbsp;e.equals(e2))</tt>. If this     * set already contains the element, the call leaves the set unchanged and     * returns <tt>false</tt>.     *     * @param e element to be added to this set     * @return <tt>true</tt> if this set did not already contain the specified     * element     */    @Override    public boolean add(E e) {        return map.put(e, PRESENT) == null;    }    /**     * Removes the specified element from this set if it is present. More     * formally, removes an element <tt>e</tt> such that     * <tt>(o==null&nbsp;?&nbsp;e==null&nbsp;:&nbsp;o.equals(e))</tt>, if this     * set contains such an element. Returns <tt>true</tt> if this set contained     * the element (or equivalently, if this set changed as a result of the     * call). (This set will not contain the element once the call returns.)     *     * @param o object to be removed from this set, if present     * @return <tt>true</tt> if the set contained the specified element     */    @Override    public boolean remove(Object o) {        return map.remove(o) == PRESENT;    }    /**     * Removes all of the elements from this set. The set will be empty after     * this call returns.     */    @Override    public void clear() {        map.clear();    }}
  • ConcurrentHashSet继承了AbstractSet,实现了Set、Serializable接口;它底层使用ConcurrentHashMap来实现,其value固定为PRESENT

实例

dubbo-2.7.2/dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/extension/SpringExtensionFactory.java

public class SpringExtensionFactory implements ExtensionFactory {    private static final Logger logger = LoggerFactory.getLogger(SpringExtensionFactory.class);    private static final Set<ApplicationContext> CONTEXTS = new ConcurrentHashSet<ApplicationContext>();    private static final ApplicationListener SHUTDOWN_HOOK_LISTENER = new ShutdownHookListener();    public static void addApplicationContext(ApplicationContext context) {        CONTEXTS.add(context);        if (context instanceof ConfigurableApplicationContext) {            ((ConfigurableApplicationContext) context).registerShutdownHook();            DubboShutdownHook.getDubboShutdownHook().unregister();        }        BeanFactoryUtils.addApplicationListener(context, SHUTDOWN_HOOK_LISTENER);    }    public static void removeApplicationContext(ApplicationContext context) {        CONTEXTS.remove(context);    }    public static Set<ApplicationContext> getContexts() {        return CONTEXTS;    }    // currently for test purpose    public static void clearContexts() {        CONTEXTS.clear();    }    @Override    @SuppressWarnings("unchecked")    public <T> T getExtension(Class<T> type, String name) {        //SPI should be get from SpiExtensionFactory        if (type.isInterface() && type.isAnnotationPresent(SPI.class)) {            return null;        }        for (ApplicationContext context : CONTEXTS) {            if (context.containsBean(name)) {                Object bean = context.getBean(name);                if (type.isInstance(bean)) {                    return (T) bean;                }            }        }        logger.warn("No spring extension (bean) named:" + name + ", try to find an extension (bean) of type " + type.getName());        if (Object.class == type) {            return null;        }        for (ApplicationContext context : CONTEXTS) {            try {                return context.getBean(type);            } catch (NoUniqueBeanDefinitionException multiBeanExe) {                logger.warn("Find more than 1 spring extensions (beans) of type " + type.getName() + ", will stop auto injection. Please make sure you have specified the concrete parameter type and there's only one extension of that type.");            } catch (NoSuchBeanDefinitionException noBeanExe) {                if (logger.isDebugEnabled()) {                    logger.debug("Error when get spring extension(bean) for type:" + type.getName(), noBeanExe);                }            }        }        logger.warn("No spring extension (bean) named:" + name + ", type:" + type.getName() + " found, stop get bean.");        return null;    }    private static class ShutdownHookListener implements ApplicationListener {        @Override        public void onApplicationEvent(ApplicationEvent event) {            if (event instanceof ContextClosedEvent) {                DubboShutdownHook shutdownHook = DubboShutdownHook.getDubboShutdownHook();                shutdownHook.doDestroy();            }        }    }}
  • SpringExtensionFactory实现了ExtensionFactory接口,它使用ConcurrentHashSet来注册spring的ApplicationContext

小结

ConcurrentHashSet继承了AbstractSet,实现了Set、Serializable接口;它底层使用ConcurrentHashMap来实现,其value固定为PRESENT

doc

  • ConcurrentHashSet