一、前言
通过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@}