ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/jsr166/jsr166/src/main/java/util/concurrent/ConcurrentMap.java
Revision: 1.59
Committed: Thu Apr 30 18:35:50 2015 UTC (9 years, 1 month ago) by jsr166
Branch: MAIN
Changes since 1.58: +35 -40 lines
Log Message:
coding style

File Contents

# User Rev Content
1 dl 1.2 /*
2     * Written by Doug Lea with assistance from members of JCP JSR-166
3 dl 1.17 * Expert Group and released to the public domain, as explained at
4 jsr166 1.31 * http://creativecommons.org/publicdomain/zero/1.0/
5 dl 1.2 */
6    
7 tim 1.1 package java.util.concurrent;
8 jsr166 1.53
9 tim 1.1 import java.util.Map;
10 dl 1.46 import java.util.Objects;
11     import java.util.function.BiConsumer;
12 dl 1.44 import java.util.function.BiFunction;
13 dl 1.46 import java.util.function.Function;
14 tim 1.1
15     /**
16 jsr166 1.43 * A {@link java.util.Map} providing thread safety and atomicity
17 dl 1.42 * guarantees.
18 dl 1.19 *
19 dl 1.55 * <p>To maintain the specified guarantees, default implementations of
20     * methods including {@link #putIfAbsent} inherited from {@link Map}
21     * must be overridden by implementations of this interface. Similarly,
22     * implementations of the collections returned by methods {@link
23     * #keySet}, {@link #values}, and {@link #entrySet} must override
24     * methods such as {@code removeIf} when necessary to
25     * preserve atomicity guarantees.
26 dl 1.46 *
27 jsr166 1.29 * <p>Memory consistency effects: As with other concurrent
28     * collections, actions in a thread prior to placing an object into a
29     * {@code ConcurrentMap} as a key or value
30     * <a href="package-summary.html#MemoryVisibility"><i>happen-before</i></a>
31     * actions subsequent to the access or removal of that object from
32     * the {@code ConcurrentMap} in another thread.
33     *
34 dl 1.19 * <p>This interface is a member of the
35 jsr166 1.30 * <a href="{@docRoot}/../technotes/guides/collections/index.html">
36 jsr166 1.47 * Java Collections Framework</a>.
37 jsr166 1.21 *
38 dl 1.4 * @since 1.5
39     * @author Doug Lea
40 dl 1.13 * @param <K> the type of keys maintained by this map
41 jsr166 1.21 * @param <V> the type of mapped values
42 dl 1.4 */
43 jsr166 1.56 public interface ConcurrentMap<K,V> extends Map<K,V> {
44 dl 1.41
45     /**
46     * {@inheritDoc}
47     *
48 dl 1.55 * @implNote This implementation assumes that the ConcurrentMap cannot
49     * contain null values and {@code get()} returning null unambiguously means
50     * the key is absent. Implementations which support null values
51     * <strong>must</strong> override this default implementation.
52 dl 1.46 *
53     * @throws ClassCastException {@inheritDoc}
54     * @throws NullPointerException {@inheritDoc}
55     * @since 1.8
56 dl 1.41 */
57     @Override
58     default V getOrDefault(Object key, V defaultValue) {
59     V v;
60     return ((v = get(key)) != null) ? v : defaultValue;
61     }
62    
63 dl 1.46 /**
64     * {@inheritDoc}
65     *
66     * @implSpec The default implementation is equivalent to, for this
67     * {@code map}:
68 jsr166 1.52 * <pre> {@code
69 jsr166 1.57 * for (Map.Entry<K,V> entry : map.entrySet()) {
70 jsr166 1.56 * action.accept(entry.getKey(), entry.getValue());
71 jsr166 1.57 * }}</pre>
72 dl 1.55 *
73     * @implNote The default implementation assumes that
74     * {@code IllegalStateException} thrown by {@code getKey()} or
75     * {@code getValue()} indicates that the entry has been removed and cannot
76     * be processed. Operation continues for subsequent entries.
77 dl 1.46 *
78     * @throws NullPointerException {@inheritDoc}
79     * @since 1.8
80     */
81     @Override
82     default void forEach(BiConsumer<? super K, ? super V> action) {
83     Objects.requireNonNull(action);
84 jsr166 1.56 for (Map.Entry<K,V> entry : entrySet()) {
85 dl 1.46 K k;
86     V v;
87     try {
88     k = entry.getKey();
89     v = entry.getValue();
90 jsr166 1.56 } catch (IllegalStateException ise) {
91 dl 1.46 // this usually means the entry is no longer in the map.
92     continue;
93     }
94     action.accept(k, v);
95     }
96     }
97    
98 tim 1.1 /**
99     * If the specified key is not already associated
100 dl 1.55 * with a value, associate it with the given value.
101     * This is equivalent to
102 jsr166 1.59 * <pre> {@code
103 dl 1.55 * if (!map.containsKey(key))
104     * return map.put(key, value);
105     * else
106 jsr166 1.59 * return map.get(key);}</pre>
107 jsr166 1.36 *
108 jsr166 1.21 * except that the action is performed atomically.
109     *
110 dl 1.55 * @implNote This implementation intentionally re-abstracts the
111     * inappropriate default provided in {@code Map}.
112 dl 1.46 *
113 jsr166 1.24 * @param key key with which the specified value is to be associated
114     * @param value value to be associated with the specified key
115 jsr166 1.25 * @return the previous value associated with the specified key, or
116 jsr166 1.38 * {@code null} if there was no mapping for the key.
117     * (A {@code null} return can also indicate that the map
118     * previously associated {@code null} with the key,
119 jsr166 1.25 * if the implementation supports null values.)
120 jsr166 1.38 * @throws UnsupportedOperationException if the {@code put} operation
121 jsr166 1.24 * is not supported by this map
122 tim 1.1 * @throws ClassCastException if the class of the specified key or value
123 jsr166 1.24 * prevents it from being stored in this map
124     * @throws NullPointerException if the specified key or value is null,
125     * and this map does not permit null keys or values
126     * @throws IllegalArgumentException if some property of the specified key
127     * or value prevents it from being stored in this map
128 dl 1.18 */
129 jsr166 1.57 V putIfAbsent(K key, V value);
130 dl 1.6
131     /**
132 jsr166 1.21 * Removes the entry for a key only if currently mapped to a given value.
133 dl 1.55 * This is equivalent to
134 jsr166 1.59 * <pre> {@code
135 dl 1.55 * if (map.containsKey(key) && Objects.equals(map.get(key), value)) {
136 jsr166 1.36 * map.remove(key);
137     * return true;
138 jsr166 1.59 * } else {
139 dl 1.55 * return false;
140 jsr166 1.59 * }}</pre>
141 jsr166 1.36 *
142 dl 1.6 * except that the action is performed atomically.
143 jsr166 1.21 *
144 dl 1.55 * @implNote This implementation intentionally re-abstracts the
145     * inappropriate default provided in {@code Map}.
146 dl 1.46 *
147 jsr166 1.24 * @param key key with which the specified value is associated
148 jsr166 1.25 * @param value value expected to be associated with the specified key
149 jsr166 1.38 * @return {@code true} if the value was removed
150     * @throws UnsupportedOperationException if the {@code remove} operation
151 jsr166 1.24 * is not supported by this map
152 jsr166 1.25 * @throws ClassCastException if the key or value is of an inappropriate
153 jsr166 1.35 * type for this map
154 dl 1.33 * (<a href="../Collection.html#optional-restrictions">optional</a>)
155 jsr166 1.24 * @throws NullPointerException if the specified key or value is null,
156 dl 1.32 * and this map does not permit null keys or values
157 dl 1.33 * (<a href="../Collection.html#optional-restrictions">optional</a>)
158 dl 1.6 */
159 dl 1.7 boolean remove(Object key, Object value);
160 dl 1.14
161     /**
162 jsr166 1.21 * Replaces the entry for a key only if currently mapped to a given value.
163 dl 1.55 * This is equivalent to
164 jsr166 1.59 * <pre> {@code
165 dl 1.55 * if (map.containsKey(key) && Objects.equals(map.get(key), oldValue)) {
166 jsr166 1.36 * map.put(key, newValue);
167     * return true;
168 jsr166 1.59 * } else {
169 dl 1.55 * return false;
170 jsr166 1.59 * }}</pre>
171 jsr166 1.36 *
172 dl 1.14 * except that the action is performed atomically.
173 jsr166 1.21 *
174 dl 1.55 * @implNote This implementation intentionally re-abstracts the
175     * inappropriate default provided in {@code Map}.
176 dl 1.46 *
177 jsr166 1.24 * @param key key with which the specified value is associated
178     * @param oldValue value expected to be associated with the specified key
179     * @param newValue value to be associated with the specified key
180 jsr166 1.38 * @return {@code true} if the value was replaced
181     * @throws UnsupportedOperationException if the {@code put} operation
182 jsr166 1.24 * is not supported by this map
183 jsr166 1.25 * @throws ClassCastException if the class of a specified key or value
184     * prevents it from being stored in this map
185 jsr166 1.24 * @throws NullPointerException if a specified key or value is null,
186     * and this map does not permit null keys or values
187 jsr166 1.25 * @throws IllegalArgumentException if some property of a specified key
188     * or value prevents it from being stored in this map
189 dl 1.14 */
190     boolean replace(K key, V oldValue, V newValue);
191 dl 1.6
192 dl 1.15 /**
193 jsr166 1.21 * Replaces the entry for a key only if currently mapped to some value.
194 dl 1.55 * This is equivalent to
195 jsr166 1.59 * <pre> {@code
196 dl 1.55 * if (map.containsKey(key)) {
197 jsr166 1.36 * return map.put(key, value);
198 jsr166 1.59 * } else {
199 dl 1.55 * return null;
200 jsr166 1.59 * }}</pre>
201 jsr166 1.36 *
202 dl 1.15 * except that the action is performed atomically.
203 jsr166 1.21 *
204 dl 1.55 * @implNote This implementation intentionally re-abstracts the
205     * inappropriate default provided in {@code Map}.
206 dl 1.46 *
207 jsr166 1.24 * @param key key with which the specified value is associated
208     * @param value value to be associated with the specified key
209 jsr166 1.25 * @return the previous value associated with the specified key, or
210 jsr166 1.38 * {@code null} if there was no mapping for the key.
211     * (A {@code null} return can also indicate that the map
212     * previously associated {@code null} with the key,
213 jsr166 1.25 * if the implementation supports null values.)
214 jsr166 1.38 * @throws UnsupportedOperationException if the {@code put} operation
215 jsr166 1.24 * is not supported by this map
216 jsr166 1.25 * @throws ClassCastException if the class of the specified key or value
217     * prevents it from being stored in this map
218 jsr166 1.24 * @throws NullPointerException if the specified key or value is null,
219     * and this map does not permit null keys or values
220 jsr166 1.25 * @throws IllegalArgumentException if some property of the specified key
221     * or value prevents it from being stored in this map
222 dl 1.15 */
223 dl 1.16 V replace(K key, V value);
224 dl 1.44
225     /**
226     * {@inheritDoc}
227     *
228 dl 1.46 * @implSpec
229     * <p>The default implementation is equivalent to, for this {@code map}:
230 jsr166 1.52 * <pre> {@code
231 jsr166 1.57 * for (Map.Entry<K,V> entry : map.entrySet()) {
232 jsr166 1.56 * do {
233     * K k = entry.getKey();
234     * V v = entry.getValue();
235     * } while (!replace(k, v, function.apply(k, v)));
236 jsr166 1.57 * }}</pre>
237 dl 1.46 *
238     * The default implementation may retry these steps when multiple
239 dl 1.55 * threads attempt updates including potentially calling the function
240     * repeatedly for a given key.
241     *
242     * <p>This implementation assumes that the ConcurrentMap cannot contain null
243     * values and {@code get()} returning null unambiguously means the key is
244     * absent. Implementations which support null values <strong>must</strong>
245     * override this default implementation.
246 dl 1.46 *
247     * @throws UnsupportedOperationException {@inheritDoc}
248     * @throws NullPointerException {@inheritDoc}
249     * @throws ClassCastException {@inheritDoc}
250     * @throws IllegalArgumentException {@inheritDoc}
251     * @since 1.8
252 dl 1.44 */
253     @Override
254     default void replaceAll(BiFunction<? super K, ? super V, ? extends V> function) {
255 dl 1.46 Objects.requireNonNull(function);
256     forEach((k,v) -> {
257 jsr166 1.56 while (!replace(k, v, function.apply(k, v))) {
258 dl 1.46 // v changed or k is gone
259     if ( (v = get(k)) == null) {
260     // k is no longer in the map.
261     break;
262     }
263 dl 1.44 }
264 dl 1.46 });
265     }
266    
267     /**
268     * {@inheritDoc}
269     *
270     * @implSpec
271     * The default implementation is equivalent to the following steps for this
272     * {@code map}, then returning the current value or {@code null} if now
273     * absent:
274     *
275 jsr166 1.52 * <pre> {@code
276 dl 1.46 * if (map.get(key) == null) {
277 jsr166 1.59 * V newValue = mappingFunction.apply(key);
278     * if (newValue != null)
279     * return map.putIfAbsent(key, newValue);
280     * }}</pre>
281 dl 1.46 *
282     * The default implementation may retry these steps when multiple
283 dl 1.55 * threads attempt updates including potentially calling the mapping
284     * function multiple times.
285     *
286     * <p>This implementation assumes that the ConcurrentMap cannot contain null
287     * values and {@code get()} returning null unambiguously means the key is
288     * absent. Implementations which support null values <strong>must</strong>
289     * override this default implementation.
290 dl 1.46 *
291     * @throws UnsupportedOperationException {@inheritDoc}
292     * @throws ClassCastException {@inheritDoc}
293     * @throws NullPointerException {@inheritDoc}
294     * @since 1.8
295     */
296     @Override
297     default V computeIfAbsent(K key,
298     Function<? super K, ? extends V> mappingFunction) {
299     Objects.requireNonNull(mappingFunction);
300     V v, newValue;
301     return ((v = get(key)) == null &&
302     (newValue = mappingFunction.apply(key)) != null &&
303     (v = putIfAbsent(key, newValue)) == null) ? newValue : v;
304     }
305 dl 1.44
306 dl 1.46 /**
307     * {@inheritDoc}
308     *
309     * @implSpec
310     * The default implementation is equivalent to performing the following
311     * steps for this {@code map}, then returning the current value or
312 jsr166 1.59 * {@code null} if now absent:
313 dl 1.46 *
314 jsr166 1.52 * <pre> {@code
315 dl 1.46 * if (map.get(key) != null) {
316 jsr166 1.59 * V oldValue = map.get(key);
317     * V newValue = remappingFunction.apply(key, oldValue);
318     * if (newValue != null)
319     * map.replace(key, oldValue, newValue);
320     * else
321     * map.remove(key, oldValue);
322     * }}</pre>
323 dl 1.46 *
324 dl 1.55 * The default implementation may retry these steps when multiple threads
325     * attempt updates including potentially calling the remapping function
326 dl 1.46 * multiple times.
327     *
328 dl 1.55 * <p>This implementation assumes that the ConcurrentMap cannot contain null
329     * values and {@code get()} returning null unambiguously means the key is
330     * absent. Implementations which support null values <strong>must</strong>
331     * override this default implementation.
332     *
333 dl 1.46 * @throws UnsupportedOperationException {@inheritDoc}
334     * @throws ClassCastException {@inheritDoc}
335     * @throws NullPointerException {@inheritDoc}
336     * @since 1.8
337     */
338     @Override
339     default V computeIfPresent(K key,
340     BiFunction<? super K, ? super V, ? extends V> remappingFunction) {
341     Objects.requireNonNull(remappingFunction);
342     V oldValue;
343 jsr166 1.56 while ((oldValue = get(key)) != null) {
344 dl 1.46 V newValue = remappingFunction.apply(key, oldValue);
345     if (newValue != null) {
346     if (replace(key, oldValue, newValue))
347     return newValue;
348     } else if (remove(key, oldValue))
349 jsr166 1.57 return null;
350 dl 1.46 }
351     return oldValue;
352     }
353    
354     /**
355     * {@inheritDoc}
356     *
357     * @implSpec
358     * The default implementation is equivalent to performing the following
359     * steps for this {@code map}, then returning the current value or
360     * {@code null} if absent:
361     *
362 jsr166 1.52 * <pre> {@code
363 dl 1.46 * V oldValue = map.get(key);
364     * V newValue = remappingFunction.apply(key, oldValue);
365     * if (oldValue != null ) {
366 jsr166 1.59 * if (newValue != null)
367     * map.replace(key, oldValue, newValue);
368     * else
369     * map.remove(key, oldValue);
370 dl 1.46 * } else {
371 jsr166 1.59 * if (newValue != null)
372     * map.putIfAbsent(key, newValue);
373     * else
374     * return null;
375     * }}</pre>
376 dl 1.46 *
377     * The default implementation may retry these steps when multiple
378 dl 1.55 * threads attempt updates including potentially calling the remapping
379     * function multiple times.
380     *
381     * <p>This implementation assumes that the ConcurrentMap cannot contain null
382     * values and {@code get()} returning null unambiguously means the key is
383     * absent. Implementations which support null values <strong>must</strong>
384     * override this default implementation.
385 dl 1.46 *
386     * @throws UnsupportedOperationException {@inheritDoc}
387     * @throws ClassCastException {@inheritDoc}
388     * @throws NullPointerException {@inheritDoc}
389     * @since 1.8
390     */
391     @Override
392     default V compute(K key,
393     BiFunction<? super K, ? super V, ? extends V> remappingFunction) {
394     Objects.requireNonNull(remappingFunction);
395     V oldValue = get(key);
396 jsr166 1.56 for (;;) {
397 dl 1.46 V newValue = remappingFunction.apply(key, oldValue);
398     if (newValue == null) {
399     // delete mapping
400     if (oldValue != null || containsKey(key)) {
401     // something to remove
402     if (remove(key, oldValue)) {
403     // removed the old value as expected
404     return null;
405     }
406    
407     // some other value replaced old value. try again.
408     oldValue = get(key);
409     } else {
410     // nothing to do. Leave things as they were.
411     return null;
412     }
413     } else {
414     // add or replace old mapping
415     if (oldValue != null) {
416     // replace
417     if (replace(key, oldValue, newValue)) {
418     // replaced as expected.
419     return newValue;
420     }
421    
422     // some other value replaced old value. try again.
423     oldValue = get(key);
424     } else {
425     // add (replace if oldValue was null)
426     if ((oldValue = putIfAbsent(key, newValue)) == null) {
427     // replaced
428     return newValue;
429     }
430    
431     // some other value replaced old value. try again.
432     }
433 dl 1.44 }
434     }
435     }
436    
437 dl 1.46 /**
438     * {@inheritDoc}
439     *
440     * @implSpec
441     * The default implementation is equivalent to performing the following
442     * steps for this {@code map}, then returning the current value or
443     * {@code null} if absent:
444     *
445 jsr166 1.52 * <pre> {@code
446 dl 1.46 * V oldValue = map.get(key);
447     * V newValue = (oldValue == null) ? value :
448 jsr166 1.59 * remappingFunction.apply(oldValue, value);
449 dl 1.46 * if (newValue == null)
450 jsr166 1.59 * map.remove(key);
451 dl 1.46 * else
452 jsr166 1.59 * map.put(key, newValue);}</pre>
453 dl 1.46 *
454 dl 1.55 * <p>The default implementation may retry these steps when multiple
455     * threads attempt updates including potentially calling the remapping
456     * function multiple times.
457     *
458     * <p>This implementation assumes that the ConcurrentMap cannot contain null
459     * values and {@code get()} returning null unambiguously means the key is
460     * absent. Implementations which support null values <strong>must</strong>
461     * override this default implementation.
462 dl 1.46 *
463     * @throws UnsupportedOperationException {@inheritDoc}
464     * @throws ClassCastException {@inheritDoc}
465     * @throws NullPointerException {@inheritDoc}
466     * @since 1.8
467     */
468     @Override
469     default V merge(K key, V value,
470     BiFunction<? super V, ? super V, ? extends V> remappingFunction) {
471     Objects.requireNonNull(remappingFunction);
472     Objects.requireNonNull(value);
473     V oldValue = get(key);
474     for (;;) {
475     if (oldValue != null) {
476     V newValue = remappingFunction.apply(oldValue, value);
477     if (newValue != null) {
478     if (replace(key, oldValue, newValue))
479     return newValue;
480     } else if (remove(key, oldValue)) {
481     return null;
482     }
483     oldValue = get(key);
484     } else {
485     if ((oldValue = putIfAbsent(key, value)) == null) {
486     return value;
487     }
488     }
489     }
490     }
491 tim 1.1 }