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