TreeMap不是线程安全性的。如果多线程并发访问一个Map对象,当某些线程对该map对象进行结构上的修改时,该map必须要实现同步(结构上的修改是指添加或删除操作,如果仅仅是修改value值,则不是结构上的修改)。可以使用java同步包装器Collections.synchronizedSortedMap实现同步功能。什么是同步包装器?同步线程包装器是为“原集合对象”的实际操作找一个代理对象,代理在“原集合对象”的一切功能之上又增加了同步功能(只是对这个“代理对象”上的操作同步,“原集合对象”上的操作非同步)。java同步线程包装器:
public static Collection synchronizedCollection(Collection c); public static Set synchronizedSet(Set s); public static List synchronizedList(List list); public static Map synchronizedMap(Map m); public static SortedSet synchronizedSortedSet(SortedSet s); public static SortedMap synchronizedSortedMap(SortedMap m);
java的同步线程包装器是有条件的同步,只有对集合的原子粒度的操作才同步。对于有并发情况的迭代操作(如Iterator是非线程安全性的),因为迭代操作是通过对对像集的调用间接操作原对像,所以在迭代时要对迭代的对像实现再同步。 SortedMap m = Collections.synchronizedSortedMap(new TreeMap()); ... Set s = m.keySet(); // Needn't be in synchronized block ... synchronized (m) { // Synchronizing on m, not s! Iterator i = s.iterator(); // Must be in synchronized block while (i.hasNext()) foo(i.next()); }
SortedMap m = Collections.synchronizedSortedMap(new TreeMap());
synchronizedSortedMap源码如下:
/** * Returns a synchronized (thread-safe) sorted map backed by the specified * sorted map. In order to guarantee serial access, it is critical that * <strong>all</strong> access to the backing sorted map is accomplished * through the returned sorted map (or its views).<p> * * It is imperative that the user manually synchronize on the returned * sorted map when iterating over any of its collection views, or the * collections views of any of its <tt>subMap</tt>, <tt>headMap</tt> or * <tt>tailMap</tt> views. * <pre> * SortedMap m = Collections.synchronizedSortedMap(new TreeMap()); * ... * Set s = m.keySet(); // Needn't be in synchronized block * ... * synchronized (m) { // Synchronizing on m, not s! * Iterator i = s.iterator(); // Must be in synchronized block * while (i.hasNext()) * foo(i.next()); * } * </pre> * or: * <pre> * SortedMap m = Collections.synchronizedSortedMap(new TreeMap()); * SortedMap m2 = m.subMap(foo, bar); * ... * Set s2 = m2.keySet(); // Needn't be in synchronized block * ... * synchronized (m) { // Synchronizing on m, not m2 or s2! * Iterator i = s.iterator(); // Must be in synchronized block * while (i.hasNext()) * foo(i.next()); * } * </pre> * Failure to follow this advice may result in non-deterministic behavior. * * <p>The returned sorted map will be serializable if the specified * sorted map is serializable. * * @param m the sorted map to be "wrapped" in a synchronized sorted map. * @return a synchronized view of the specified sorted map. */ public static <K,V> SortedMap<K,V> synchronizedSortedMap(SortedMap<K,V> m) { return new SynchronizedSortedMap<>(m); }
看到其调用了SynchronizedSortedMap的构造方法,SynchronizedSortedMap是Collections类中的内部类,SynchronizedSortedMap源码如下: /** * @serial include */ static class SynchronizedSortedMap<K,V> extends SynchronizedMap<K,V> implements SortedMap<K,V> { private static final long serialVersionUID = -8798146769416483793L; private final SortedMap<K,V> sm; SynchronizedSortedMap(SortedMap<K,V> m) { super(m); sm = m; } SynchronizedSortedMap(SortedMap<K,V> m, Object mutex) { super(m, mutex); sm = m; } public Comparator<? super K> comparator() { synchronized (mutex) {return sm.comparator();} } public SortedMap<K,V> subMap(K fromKey, K toKey) { synchronized (mutex) { return new SynchronizedSortedMap<>( sm.subMap(fromKey, toKey), mutex); } } public SortedMap<K,V> headMap(K toKey) { synchronized (mutex) { return new SynchronizedSortedMap<>(sm.headMap(toKey), mutex); } } public SortedMap<K,V> tailMap(K fromKey) { synchronized (mutex) { return new SynchronizedSortedMap<>(sm.tailMap(fromKey),mutex); } } public K firstKey() { synchronized (mutex) {return sm.firstKey();} } public K lastKey() { synchronized (mutex) {return sm.lastKey();} } }
上述代码中用同步方法synchronized加锁的mutex是父类SynchronizedMap中的属性,代表当前对象,SynchronizedMap的源码如下:
/** * Returns a synchronized (thread-safe) map backed by the specified * map. In order to guarantee serial access, it is critical that * <strong>all</strong> access to the backing map is accomplished * through the returned map.<p> * * It is imperative that the user manually synchronize on the returned * map when iterating over any of its collection views: * <pre> * Map m = Collections.synchronizedMap(new HashMap()); * ... * Set s = m.keySet(); // Needn't be in synchronized block * ... * synchronized (m) { // Synchronizing on m, not s! * Iterator i = s.iterator(); // Must be in synchronized block * while (i.hasNext()) * foo(i.next()); * } * </pre> * Failure to follow this advice may result in non-deterministic behavior. * * <p>The returned map will be serializable if the specified map is * serializable. * * @param m the map to be "wrapped" in a synchronized map. * @return a synchronized view of the specified map. */ public static <K,V> Map<K,V> synchronizedMap(Map<K,V> m) { return new SynchronizedMap<>(m); } /** * @serial include */ private static class SynchronizedMap<K,V> implements Map<K,V>, Serializable { private static final long serialVersionUID = 1978198479659022715L; private final Map<K,V> m; // Backing Map final Object mutex; // Object on which to synchronize SynchronizedMap(Map<K,V> m) { if (m==null) throw new NullPointerException(); this.m = m; mutex = this; } SynchronizedMap(Map<K,V> m, Object mutex) { this.m = m; this.mutex = mutex; } public int size() { synchronized (mutex) {return m.size();} } public boolean isEmpty() { synchronized (mutex) {return m.isEmpty();} } public boolean containsKey(Object key) { synchronized (mutex) {return m.containsKey(key);} } public boolean containsValue(Object value) { synchronized (mutex) {return m.containsValue(value);} } public V get(Object key) { synchronized (mutex) {return m.get(key);} } public V put(K key, V value) { synchronized (mutex) {return m.put(key, value);} } public V remove(Object key) { synchronized (mutex) {return m.remove(key);} } public void putAll(Map<? extends K, ? extends V> map) { synchronized (mutex) {m.putAll(map);} } public void clear() { synchronized (mutex) {m.clear();} } private transient Set<K> keySet = null; private transient Set<Map.Entry<K,V>> entrySet = null; private transient Collection<V> values = null; public Set<K> keySet() { synchronized (mutex) { if (keySet==null) keySet = new SynchronizedSet<>(m.keySet(), mutex); return keySet; } } public Set<Map.Entry<K,V>> entrySet() { synchronized (mutex) { if (entrySet==null) entrySet = new SynchronizedSet<>(m.entrySet(), mutex); return entrySet; } } public Collection<V> values() { synchronized (mutex) { if (values==null) values = new SynchronizedCollection<>(m.values(), mutex); return values; } } public boolean equals(Object o) { synchronized (mutex) {return m.equals(o);} } public int hashCode() { synchronized (mutex) {return m.hashCode();} } public String toString() { synchronized (mutex) {return m.toString();} } private void writeObject(ObjectOutputStream s) throws IOException { synchronized (mutex) {s.defaultWriteObject();} } }