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 }