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 import com.atlassian.util.concurrent.CopyOnWriteMaps;
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 {
62 private static final long serialVersionUID = 7935514534647505917L;
63
64 /**
65 * Creates a new {@link CopyOnWriteMap} with an underlying {@link HashMap}.
66 */
67 public static <K, V> CopyOnWriteMap<K, V> newHashMap()
68 {
69 return new CopyOnWriteMap<K, V>()
70 {
71 private static final long serialVersionUID = 5221824943734164497L;
72
73 @Override
74 public <N extends Map<? extends K, ? extends V>> Map<K, V> copy(final N map)
75 {
76 return new HashMap<K, V>(map);
77 }
78 };
79 }
80
81 /**
82 * Creates a new {@link CopyOnWriteMap} with an underlying {@link HashMap}
83 * using the supplied map as the initial values.
84 */
85 public static <K, V> CopyOnWriteMap<K, V> newHashMap(final Map<? extends K, ? extends V> map)
86 {
87 return new CopyOnWriteMap<K, V>(map)
88 {
89 private static final long serialVersionUID = -7616159260882572421L;
90
91 @Override
92 public <N extends Map<? extends K, ? extends V>> Map<K, V> copy(final N map)
93 {
94 return new HashMap<K, V>(map);
95 }
96 };
97 }
98
99 /**
100 * Creates a new {@link CopyOnWriteMap} with an underlying
101 * {@link LinkedHashMap}. Iterators for this map will be return elements in
102 * insertion order.
103 */
104 public static <K, V> CopyOnWriteMap<K, V> newLinkedMap()
105 {
106 return new CopyOnWriteMap<K, V>()
107 {
108 private static final long serialVersionUID = -4597421704607601676L;
109
110 @Override
111 public <N extends Map<? extends K, ? extends V>> Map<K, V> copy(final N map)
112 {
113 return new LinkedHashMap<K, V>(map);
114 }
115 };
116 }
117
118 /**
119 * Creates a new {@link CopyOnWriteMap} with an underlying
120 * {@link LinkedHashMap} using the supplied map as the initial values.
121 * Iterators for this map will be return elements in insertion order.
122 */
123 public static <K, V> CopyOnWriteMap<K, V> newLinkedMap(final Map<? extends K, ? extends V> map)
124 {
125 return new CopyOnWriteMap<K, V>(map)
126 {
127 private static final long serialVersionUID = -8659999465009072124L;
128
129 @Override
130 public <N extends Map<? extends K, ? extends V>> Map<K, V> copy(final N map)
131 {
132 return new LinkedHashMap<K, V>(map);
133 }
134 };
135 }
136
137 //
138 // constructors
139 //
140
141 /**
142 * Create a new {@link CopyOnWriteMap} with the supplied {@link Map} to
143 * initialize the values.
144 *
145 * @param map the initial map to initialize with
146 */
147 public CopyOnWriteMap(final Map<? extends K, ? extends V> map)
148 {
149 super(map);
150 }
151
152 /**
153 * Create a new empty {@link CopyOnWriteMap}.
154 */
155 public CopyOnWriteMap()
156 {
157 super(Collections.<K, V> emptyMap());
158 }
159 }