View Javadoc
1   package com.atlassian.plugin.util.concurrent;
2   
3   import com.atlassian.util.concurrent.CopyOnWriteMaps;
4   
5   import java.util.Collections;
6   import java.util.HashMap;
7   import java.util.LinkedHashMap;
8   import java.util.Map;
9   import java.util.TreeMap;
10  import java.util.WeakHashMap;
11  
12  /**
13   * A thread-safe variant of {@link Map} in which all mutative operations (the
14   * "destructive" operations described by {@link Map} put, remove and so on) are
15   * implemented by making a fresh copy of the underlying map.
16   * <p>
17   * This is ordinarily too costly, but may be <em>more</em> efficient than
18   * alternatives when traversal operations vastly out-number mutations, and is
19   * useful when you cannot or don't want to synchronize traversals, yet need to
20   * preclude interference among concurrent threads. The "snapshot" style
21   * iterators on the collections returned by {@link #entrySet()},
22   * {@link #keySet()} and {@link #values()} use a reference to the internal map
23   * at the point that the iterator was created. This map never changes during the
24   * lifetime of the iterator, so interference is impossible and the iterator is
25   * guaranteed not to throw <tt>ConcurrentModificationException</tt>. The
26   * iterators will not reflect additions, removals, or changes to the list since
27   * the iterator was created. Removing elements via these iterators is not
28   * supported. The mutable operations on these collections (remove, retain etc.)
29   * are supported but as with the {@link Map} interface, add and addAll are not
30   * and throw {@link UnsupportedOperationException}.
31   * <p>
32   * The actual copy is performed by an abstract {@link #copy(Map)} method. The
33   * method is responsible for the underlying Map implementation (for instance a
34   * {@link HashMap}, {@link TreeMap}, {@link LinkedHashMap} etc.) and therefore
35   * the semantics of what this map will cope with as far as null keys and values,
36   * iteration ordering etc. See the note below about suitable candidates for
37   * underlying Map implementations
38   * <p>
39   * There are supplied implementations for the common Collections {@link Map}
40   * implementations via the {@link CopyOnWriteMaps} static factory methods.
41   * <p>
42   * Collection views of the keys, values and entries are modifiable and will
43   * cause a copy.
44   * <p>
45   * <strong>Please note</strong> that the thread-safety guarantees are limited to
46   * the thread-safety of the non-mutative (non-destructive) operations of the
47   * underlying map implementation. For instance some implementations such as
48   * {@link WeakHashMap} and {@link LinkedHashMap} with access ordering are
49   * actually structurally modified by the {@link #get(Object)} method and are
50   * therefore not suitable candidates as delegates for this class.
51   *
52   * @param <K> the key type
53   * @param <V> the value type
54   * @deprecated since 2.5.0 please use the
55   * {@link com.atlassian.util.concurrent.CopyOnWriteMap} instead as
56   * it has some important features and some bug fixes. This version
57   * is no longer maintained.
58   */
59  @Deprecated
60  public abstract class CopyOnWriteMap<K, V> extends com.atlassian.util.concurrent.CopyOnWriteMap<K, V> {
61      private static final long serialVersionUID = 7935514534647505917L;
62  
63      /**
64       * Creates a new {@link CopyOnWriteMap} with an underlying {@link HashMap}.
65       */
66      public static <K, V> CopyOnWriteMap<K, V> newHashMap() {
67          return new CopyOnWriteMap<K, V>() {
68              private static final long serialVersionUID = 5221824943734164497L;
69  
70              @Override
71              public <N extends Map<? extends K, ? extends V>> Map<K, V> copy(final N map) {
72                  return new HashMap<K, V>(map);
73              }
74          };
75      }
76  
77      /**
78       * Creates a new {@link CopyOnWriteMap} with an underlying {@link HashMap}
79       * using the supplied map as the initial values.
80       */
81      public static <K, V> CopyOnWriteMap<K, V> newHashMap(final Map<? extends K, ? extends V> map) {
82          return new CopyOnWriteMap<K, V>(map) {
83              private static final long serialVersionUID = -7616159260882572421L;
84  
85              @Override
86              public <N extends Map<? extends K, ? extends V>> Map<K, V> copy(final N map) {
87                  return new HashMap<K, V>(map);
88              }
89          };
90      }
91  
92      /**
93       * Creates a new {@link CopyOnWriteMap} with an underlying
94       * {@link LinkedHashMap}. Iterators for this map will be return elements in
95       * insertion order.
96       */
97      public static <K, V> CopyOnWriteMap<K, V> newLinkedMap() {
98          return new CopyOnWriteMap<K, V>() {
99              private static final long serialVersionUID = -4597421704607601676L;
100 
101             @Override
102             public <N extends Map<? extends K, ? extends V>> Map<K, V> copy(final N map) {
103                 return new LinkedHashMap<K, V>(map);
104             }
105         };
106     }
107 
108     /**
109      * Creates a new {@link CopyOnWriteMap} with an underlying
110      * {@link LinkedHashMap} using the supplied map as the initial values.
111      * Iterators for this map will be return elements in insertion order.
112      */
113     public static <K, V> CopyOnWriteMap<K, V> newLinkedMap(final Map<? extends K, ? extends V> map) {
114         return new CopyOnWriteMap<K, V>(map) {
115             private static final long serialVersionUID = -8659999465009072124L;
116 
117             @Override
118             public <N extends Map<? extends K, ? extends V>> Map<K, V> copy(final N map) {
119                 return new LinkedHashMap<K, V>(map);
120             }
121         };
122     }
123 
124     //
125     // constructors
126     //
127 
128     /**
129      * Create a new {@link CopyOnWriteMap} with the supplied {@link Map} to
130      * initialize the values.
131      *
132      * @param map the initial map to initialize with
133      */
134     public CopyOnWriteMap(final Map<? extends K, ? extends V> map) {
135         super(map);
136     }
137 
138     /**
139      * Create a new empty {@link CopyOnWriteMap}.
140      */
141     public CopyOnWriteMap() {
142         super(Collections.<K, V>emptyMap());
143     }
144 }