View Javadoc

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