首页

分享Apache的commons-beanutils自定义FastHashMap通过synchronized增强HashMap非线程安全的不足

标签:FastHashMap,HashMap非线程安全,apache,commons-beanutils,自定义Map     发布时间:2018-01-07   

一、前言

通过apache的commons-beanutils源码包(1.8.3)中的org.apache.commons.collections.FastHashMap继承HashMap,并通过synchronized的方式实现解决了HashMap非线程安全问题,可以根据setFast(true)来切换是否开关(false为使用线程安全模式),当然通过Collections.synchronizedMap(map)的方式通用可以实现HashMap的线程安全。

二、源码说明

    @b@package org.apache.commons.collections;@b@@b@import java.util.Collection;@b@import java.util.ConcurrentModificationException;@b@import java.util.HashMap;@b@import java.util.Iterator;@b@import java.util.Map;@b@import java.util.Set;@b@@b@public class FastHashMap extends HashMap {@b@@b@    /**@b@     * The underlying map we are managing.@b@     */@b@    protected HashMap map = null;@b@@b@    /**@b@     * Are we currently operating in "fast" mode?@b@     */@b@    protected boolean fast = false;@b@@b@    // Constructors@b@    // ----------------------------------------------------------------------@b@@b@    /**@b@     * Construct an empty map.@b@     */@b@    public FastHashMap() {@b@        super();@b@        this.map = new HashMap();@b@    }@b@@b@    /**@b@     * Construct an empty map with the specified capacity.@b@     *@b@     * @param capacity  the initial capacity of the empty map@b@     */@b@    public FastHashMap(int capacity) {@b@        super();@b@        this.map = new HashMap(capacity);@b@    }@b@@b@    /**@b@     * Construct an empty map with the specified capacity and load factor.@b@     *@b@     * @param capacity  the initial capacity of the empty map@b@     * @param factor  the load factor of the new map@b@     */@b@    public FastHashMap(int capacity, float factor) {@b@        super();@b@        this.map = new HashMap(capacity, factor);@b@    }@b@@b@    /**@b@     * Construct a new map with the same mappings as the specified map.@b@     *@b@     * @param map  the map whose mappings are to be copied@b@     */@b@    public FastHashMap(Map map) {@b@        super();@b@        this.map = new HashMap(map);@b@    }@b@@b@@b@    // Property access@b@    // ----------------------------------------------------------------------@b@@b@    /**@b@     *  Returns true if this map is operating in fast mode.@b@     *@b@     *  @return true if this map is operating in fast mode@b@     */@b@    public boolean getFast() {@b@        return (this.fast);@b@    }@b@@b@    /**@b@     *  Sets whether this map is operating in fast mode.@b@     *@b@     *  @param fast true if this map should operate in fast mode@b@     */@b@    public void setFast(boolean fast) {@b@        this.fast = fast;@b@    }@b@@b@@b@    // Map access@b@    // ----------------------------------------------------------------------@b@    // These methods can forward straight to the wrapped Map in 'fast' mode.@b@    // (because they are query methods)@b@@b@    /**@b@     * Return the value to which this map maps the specified key.  Returns@b@     * <code>null</code> if the map contains no mapping for this key, or if@b@     * there is a mapping with a value of <code>null</code>.  Use the@b@     * <code>containsKey()</code> method to disambiguate these cases.@b@     *@b@     * @param key  the key whose value is to be returned@b@     * @return the value mapped to that key, or null@b@     */@b@    public Object get(Object key) {@b@        if (fast) {@b@            return (map.get(key));@b@        } else {@b@            synchronized (map) {@b@                return (map.get(key));@b@            }@b@        }@b@    }@b@@b@    /**@b@     * Return the number of key-value mappings in this map.@b@     * @b@     * @return the current size of the map@b@     */@b@    public int size() {@b@        if (fast) {@b@            return (map.size());@b@        } else {@b@            synchronized (map) {@b@                return (map.size());@b@            }@b@        }@b@    }@b@@b@    /**@b@     * Return <code>true</code> if this map contains no mappings.@b@     * @b@     * @return is the map currently empty@b@     */@b@    public boolean isEmpty() {@b@        if (fast) {@b@            return (map.isEmpty());@b@        } else {@b@            synchronized (map) {@b@                return (map.isEmpty());@b@            }@b@        }@b@    }@b@@b@    /**@b@     * Return <code>true</code> if this map contains a mapping for the@b@     * specified key.@b@     *@b@     * @param key  the key to be searched for@b@     * @return true if the map contains the key@b@     */@b@    public boolean containsKey(Object key) {@b@        if (fast) {@b@            return (map.containsKey(key));@b@        } else {@b@            synchronized (map) {@b@                return (map.containsKey(key));@b@            }@b@        }@b@    }@b@@b@    /**@b@     * Return <code>true</code> if this map contains one or more keys mapping@b@     * to the specified value.@b@     *@b@     * @param value  the value to be searched for@b@     * @return true if the map contains the value@b@     */@b@    public boolean containsValue(Object value) {@b@        if (fast) {@b@            return (map.containsValue(value));@b@        } else {@b@            synchronized (map) {@b@                return (map.containsValue(value));@b@            }@b@        }@b@    }@b@@b@    // Map modification@b@    // ----------------------------------------------------------------------@b@    // These methods perform special behaviour in 'fast' mode.@b@    // The map is cloned, updated and then assigned back.@b@    // See the comments at the top as to why this won't always work.@b@@b@    /**@b@     * Associate the specified value with the specified key in this map.@b@     * If the map previously contained a mapping for this key, the old@b@     * value is replaced and returned.@b@     *@b@     * @param key  the key with which the value is to be associated@b@     * @param value  the value to be associated with this key@b@     * @return the value previously mapped to the key, or null@b@     */@b@    public Object put(Object key, Object value) {@b@        if (fast) {@b@            synchronized (this) {@b@                HashMap temp = (HashMap) map.clone();@b@                Object result = temp.put(key, value);@b@                map = temp;@b@                return (result);@b@            }@b@        } else {@b@            synchronized (map) {@b@                return (map.put(key, value));@b@            }@b@        }@b@    }@b@@b@    /**@b@     * Copy all of the mappings from the specified map to this one, replacing@b@     * any mappings with the same keys.@b@     *@b@     * @param in  the map whose mappings are to be copied@b@     */@b@    public void putAll(Map in) {@b@        if (fast) {@b@            synchronized (this) {@b@                HashMap temp = (HashMap) map.clone();@b@                temp.putAll(in);@b@                map = temp;@b@            }@b@        } else {@b@            synchronized (map) {@b@                map.putAll(in);@b@            }@b@        }@b@    }@b@@b@    /**@b@     * Remove any mapping for this key, and return any previously@b@     * mapped value.@b@     *@b@     * @param key  the key whose mapping is to be removed@b@     * @return the value removed, or null@b@     */@b@    public Object remove(Object key) {@b@        if (fast) {@b@            synchronized (this) {@b@                HashMap temp = (HashMap) map.clone();@b@                Object result = temp.remove(key);@b@                map = temp;@b@                return (result);@b@            }@b@        } else {@b@            synchronized (map) {@b@                return (map.remove(key));@b@            }@b@        }@b@    }@b@@b@    /**@b@     * Remove all mappings from this map.@b@     */@b@    public void clear() {@b@        if (fast) {@b@            synchronized (this) {@b@                map = new HashMap();@b@            }@b@        } else {@b@            synchronized (map) {@b@                map.clear();@b@            }@b@        }@b@    }@b@@b@    // Basic object methods@b@    // ----------------------------------------------------------------------@b@    @b@    /**@b@     * Compare the specified object with this list for equality.  This@b@     * implementation uses exactly the code that is used to define the@b@     * list equals function in the documentation for the@b@     * <code>Map.equals</code> method.@b@     *@b@     * @param o  the object to be compared to this list@b@     * @return true if the two maps are equal@b@     */@b@    public boolean equals(Object o) {@b@        // Simple tests that require no synchronization@b@        if (o == this) {@b@            return (true);@b@        } else if (!(o instanceof Map)) {@b@            return (false);@b@        }@b@        Map mo = (Map) o;@b@@b@        // Compare the two maps for equality@b@        if (fast) {@b@            if (mo.size() != map.size()) {@b@                return (false);@b@            }@b@            Iterator i = map.entrySet().iterator();@b@            while (i.hasNext()) {@b@                Map.Entry e = (Map.Entry) i.next();@b@                Object key = e.getKey();@b@                Object value = e.getValue();@b@                if (value == null) {@b@                    if (!(mo.get(key) == null && mo.containsKey(key))) {@b@                        return (false);@b@                    }@b@                } else {@b@                    if (!value.equals(mo.get(key))) {@b@                        return (false);@b@                    }@b@                }@b@            }@b@            return (true);@b@            @b@        } else {@b@            synchronized (map) {@b@                if (mo.size() != map.size()) {@b@                    return (false);@b@                }@b@                Iterator i = map.entrySet().iterator();@b@                while (i.hasNext()) {@b@                    Map.Entry e = (Map.Entry) i.next();@b@                    Object key = e.getKey();@b@                    Object value = e.getValue();@b@                    if (value == null) {@b@                        if (!(mo.get(key) == null && mo.containsKey(key))) {@b@                            return (false);@b@                        }@b@                    } else {@b@                        if (!value.equals(mo.get(key))) {@b@                            return (false);@b@                        }@b@                    }@b@                }@b@                return (true);@b@            }@b@        }@b@    }@b@@b@    /**@b@     * Return the hash code value for this map.  This implementation uses@b@     * exactly the code that is used to define the list hash function in the@b@     * documentation for the <code>Map.hashCode</code> method.@b@     * @b@     * @return suitable integer hash code@b@     */@b@    public int hashCode() {@b@        if (fast) {@b@            int h = 0;@b@            Iterator i = map.entrySet().iterator();@b@            while (i.hasNext()) {@b@                h += i.next().hashCode();@b@            }@b@            return (h);@b@        } else {@b@            synchronized (map) {@b@                int h = 0;@b@                Iterator i = map.entrySet().iterator();@b@                while (i.hasNext()) {@b@                    h += i.next().hashCode();@b@                }@b@                return (h);@b@            }@b@        }@b@    }@b@@b@    /**@b@     * Return a shallow copy of this <code>FastHashMap</code> instance.@b@     * The keys and values themselves are not copied.@b@     * @b@     * @return a clone of this map@b@     */@b@    public Object clone() {@b@        FastHashMap results = null;@b@        if (fast) {@b@            results = new FastHashMap(map);@b@        } else {@b@            synchronized (map) {@b@                results = new FastHashMap(map);@b@            }@b@        }@b@        results.setFast(getFast());@b@        return (results);@b@    }@b@@b@    // Map views@b@    // ----------------------------------------------------------------------@b@    @b@    /**@b@     * Return a collection view of the mappings contained in this map.  Each@b@     * element in the returned collection is a <code>Map.Entry</code>.@b@     * @return the set of map Map entries@b@     */@b@    public Set entrySet() {@b@        return new EntrySet();@b@    }@b@@b@    /**@b@     * Return a set view of the keys contained in this map.@b@     * @return the set of the Map's keys@b@     */@b@    public Set keySet() {@b@        return new KeySet();@b@    }@b@@b@    /**@b@     * Return a collection view of the values contained in this map.@b@     * @return the set of the Map's values@b@     */@b@    public Collection values() {@b@        return new Values();@b@    }@b@@b@    // Map view inner classes@b@    // ----------------------------------------------------------------------@b@@b@    /**@b@     * Abstract collection implementation shared by keySet(), values() and entrySet().@b@     */@b@    private abstract class CollectionView implements Collection {@b@@b@        public CollectionView() {@b@        }@b@@b@        protected abstract Collection get(Map map);@b@        protected abstract Object iteratorNext(Map.Entry entry);@b@@b@@b@        public void clear() {@b@            if (fast) {@b@                synchronized (FastHashMap.this) {@b@                    map = new HashMap();@b@                }@b@            } else {@b@                synchronized (map) {@b@                    get(map).clear();@b@                }@b@            }@b@        }@b@@b@        public boolean remove(Object o) {@b@            if (fast) {@b@                synchronized (FastHashMap.this) {@b@                    HashMap temp = (HashMap) map.clone();@b@                    boolean r = get(temp).remove(o);@b@                    map = temp;@b@                    return r;@b@                }@b@            } else {@b@                synchronized (map) {@b@                    return get(map).remove(o);@b@                }@b@            }@b@        }@b@@b@        public boolean removeAll(Collection o) {@b@            if (fast) {@b@                synchronized (FastHashMap.this) {@b@                    HashMap temp = (HashMap) map.clone();@b@                    boolean r = get(temp).removeAll(o);@b@                    map = temp;@b@                    return r;@b@                }@b@            } else {@b@                synchronized (map) {@b@                    return get(map).removeAll(o);@b@                }@b@            }@b@        }@b@@b@        public boolean retainAll(Collection o) {@b@            if (fast) {@b@                synchronized (FastHashMap.this) {@b@                    HashMap temp = (HashMap) map.clone();@b@                    boolean r = get(temp).retainAll(o);@b@                    map = temp;@b@                    return r;@b@                }@b@            } else {@b@                synchronized (map) {@b@                    return get(map).retainAll(o);@b@                }@b@            }@b@        }@b@@b@        public int size() {@b@            if (fast) {@b@                return get(map).size();@b@            } else {@b@                synchronized (map) {@b@                    return get(map).size();@b@                }@b@            }@b@        }@b@@b@@b@        public boolean isEmpty() {@b@            if (fast) {@b@                return get(map).isEmpty();@b@            } else {@b@                synchronized (map) {@b@                    return get(map).isEmpty();@b@                }@b@            }@b@        }@b@@b@        public boolean contains(Object o) {@b@            if (fast) {@b@                return get(map).contains(o);@b@            } else {@b@                synchronized (map) {@b@                    return get(map).contains(o);@b@                }@b@            }@b@        }@b@@b@        public boolean containsAll(Collection o) {@b@            if (fast) {@b@                return get(map).containsAll(o);@b@            } else {@b@                synchronized (map) {@b@                    return get(map).containsAll(o);@b@                }@b@            }@b@        }@b@@b@        public Object[] toArray(Object[] o) {@b@            if (fast) {@b@                return get(map).toArray(o);@b@            } else {@b@                synchronized (map) {@b@                    return get(map).toArray(o);@b@                }@b@            }@b@        }@b@@b@        public Object[] toArray() {@b@            if (fast) {@b@                return get(map).toArray();@b@            } else {@b@                synchronized (map) {@b@                    return get(map).toArray();@b@                }@b@            }@b@        }@b@@b@@b@        public boolean equals(Object o) {@b@            if (o == this) {@b@                return true;@b@            }@b@            if (fast) {@b@                return get(map).equals(o);@b@            } else {@b@                synchronized (map) {@b@                    return get(map).equals(o);@b@                }@b@            }@b@        }@b@@b@        public int hashCode() {@b@            if (fast) {@b@                return get(map).hashCode();@b@            } else {@b@                synchronized (map) {@b@                    return get(map).hashCode();@b@                }@b@            }@b@        }@b@@b@        public boolean add(Object o) {@b@            throw new UnsupportedOperationException();@b@        }@b@@b@        public boolean addAll(Collection c) {@b@            throw new UnsupportedOperationException();@b@        }@b@@b@        public Iterator iterator() {@b@            return new CollectionViewIterator();@b@        }@b@@b@        private class CollectionViewIterator implements Iterator {@b@@b@            private Map expected;@b@            private Map.Entry lastReturned = null;@b@            private Iterator iterator;@b@@b@            public CollectionViewIterator() {@b@                this.expected = map;@b@                this.iterator = expected.entrySet().iterator();@b@            }@b@ @b@            public boolean hasNext() {@b@                if (expected != map) {@b@                    throw new ConcurrentModificationException();@b@                }@b@                return iterator.hasNext();@b@            }@b@@b@            public Object next() {@b@                if (expected != map) {@b@                    throw new ConcurrentModificationException();@b@                }@b@                lastReturned = (Map.Entry)iterator.next();@b@                return iteratorNext(lastReturned);@b@            }@b@@b@            public void remove() {@b@                if (lastReturned == null) {@b@                    throw new IllegalStateException();@b@                }@b@                if (fast) {@b@                    synchronized (FastHashMap.this) {@b@                        if (expected != map) {@b@                            throw new ConcurrentModificationException();@b@                        }@b@                        FastHashMap.this.remove(lastReturned.getKey());@b@                        lastReturned = null;@b@                        expected = map;@b@                    }@b@                } else {@b@                    iterator.remove();@b@                    lastReturned = null;@b@                }@b@            }@b@        }@b@    }@b@@b@    /**@b@     * Set implementation over the keys of the FastHashMap@b@     */@b@    private class KeySet extends CollectionView implements Set {@b@    @b@        protected Collection get(Map map) {@b@            return map.keySet();@b@        }@b@    @b@        protected Object iteratorNext(Map.Entry entry) {@b@            return entry.getKey();@b@        }@b@    @b@    }@b@    @b@    /**@b@     * Collection implementation over the values of the FastHashMap@b@     */@b@    private class Values extends CollectionView {@b@    @b@        protected Collection get(Map map) {@b@            return map.values();@b@        }@b@    @b@        protected Object iteratorNext(Map.Entry entry) {@b@            return entry.getValue();@b@        }@b@    }@b@    @b@    /**@b@     * Set implementation over the entries of the FastHashMap@b@     */@b@    private class EntrySet extends CollectionView implements Set {@b@    @b@        protected Collection get(Map map) {@b@            return map.entrySet();@b@        }@b@    @b@        protected Object iteratorNext(Map.Entry entry) {@b@            return entry;@b@        }@b@    @b@    }@b@@b@}