ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/jsr166/jsr166/src/main/java/util/concurrent/ConcurrentMap.java
Revision: 1.55
Committed: Wed Apr 29 11:42:13 2015 UTC (9 years, 1 month ago) by dl
Branch: MAIN
Changes since 1.54: +129 -101 lines
Log Message:
Add guidance about overrides; sync with openjdk

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 dl 1.55 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 dl 1.55 * for ((Map.Entry<K, V> entry : map.entrySet())
70     * action.accept(entry.getKey(), entry.getValue());
71     * }</pre>
72     *
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 dl 1.55 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 dl 1.55 } 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     * <pre> {@code
103     * if (!map.containsKey(key))
104     * return map.put(key, value);
105     * else
106 jsr166 1.48 * return map.get(key);
107 dl 1.55 * }</pre>
108 jsr166 1.36 *
109 jsr166 1.21 * except that the action is performed atomically.
110     *
111 dl 1.55 * @implNote This implementation intentionally re-abstracts the
112     * inappropriate default provided in {@code Map}.
113 dl 1.46 *
114 jsr166 1.24 * @param key key with which the specified value is to be associated
115     * @param value value to be associated with the specified key
116 jsr166 1.25 * @return the previous value associated with the specified key, or
117 jsr166 1.38 * {@code null} if there was no mapping for the key.
118     * (A {@code null} return can also indicate that the map
119     * previously associated {@code null} with the key,
120 jsr166 1.25 * if the implementation supports null values.)
121 jsr166 1.38 * @throws UnsupportedOperationException if the {@code put} operation
122 jsr166 1.24 * is not supported by this map
123 tim 1.1 * @throws ClassCastException if the class of the specified key or value
124 jsr166 1.24 * prevents it from being stored in this map
125     * @throws NullPointerException if the specified key or value is null,
126     * and this map does not permit null keys or values
127     * @throws IllegalArgumentException if some property of the specified key
128     * or value prevents it from being stored in this map
129 dl 1.18 */
130 dl 1.55 V putIfAbsent(K key, V value);
131 dl 1.6
132     /**
133 jsr166 1.21 * Removes the entry for a key only if currently mapped to a given value.
134 dl 1.55 * This is equivalent to
135     * <pre> {@code
136     * if (map.containsKey(key) && Objects.equals(map.get(key), value)) {
137 jsr166 1.36 * map.remove(key);
138     * return true;
139     * } else
140 dl 1.55 * return false;
141     * }</pre>
142 jsr166 1.36 *
143 dl 1.6 * except that the action is performed atomically.
144 jsr166 1.21 *
145 dl 1.55 * @implNote This implementation intentionally re-abstracts the
146     * inappropriate default provided in {@code Map}.
147 dl 1.46 *
148 jsr166 1.24 * @param key key with which the specified value is associated
149 jsr166 1.25 * @param value value expected to be associated with the specified key
150 jsr166 1.38 * @return {@code true} if the value was removed
151     * @throws UnsupportedOperationException if the {@code remove} operation
152 jsr166 1.24 * is not supported by this map
153 jsr166 1.25 * @throws ClassCastException if the key or value is of an inappropriate
154 jsr166 1.35 * type for this map
155 dl 1.33 * (<a href="../Collection.html#optional-restrictions">optional</a>)
156 jsr166 1.24 * @throws NullPointerException if the specified key or value is null,
157 dl 1.32 * and this map does not permit null keys or values
158 dl 1.33 * (<a href="../Collection.html#optional-restrictions">optional</a>)
159 dl 1.6 */
160 dl 1.7 boolean remove(Object key, Object value);
161 dl 1.14
162     /**
163 jsr166 1.21 * Replaces the entry for a key only if currently mapped to a given value.
164 dl 1.55 * This is equivalent to
165     * <pre> {@code
166     * if (map.containsKey(key) && Objects.equals(map.get(key), oldValue)) {
167 jsr166 1.36 * map.put(key, newValue);
168     * return true;
169     * } else
170 dl 1.55 * return false;
171     * }</pre>
172 jsr166 1.36 *
173 dl 1.14 * except that the action is performed atomically.
174 jsr166 1.21 *
175 dl 1.55 * @implNote This implementation intentionally re-abstracts the
176     * inappropriate default provided in {@code Map}.
177 dl 1.46 *
178 jsr166 1.24 * @param key key with which the specified value is associated
179     * @param oldValue value expected to be associated with the specified key
180     * @param newValue value to be associated with the specified key
181 jsr166 1.38 * @return {@code true} if the value was replaced
182     * @throws UnsupportedOperationException if the {@code put} operation
183 jsr166 1.24 * is not supported by this map
184 jsr166 1.25 * @throws ClassCastException if the class of a specified key or value
185     * prevents it from being stored in this map
186 jsr166 1.24 * @throws NullPointerException if a specified key or value is null,
187     * and this map does not permit null keys or values
188 jsr166 1.25 * @throws IllegalArgumentException if some property of a specified key
189     * or value prevents it from being stored in this map
190 dl 1.14 */
191     boolean replace(K key, V oldValue, V newValue);
192 dl 1.6
193 dl 1.15 /**
194 jsr166 1.21 * Replaces the entry for a key only if currently mapped to some value.
195 dl 1.55 * This is equivalent to
196     * <pre> {@code
197     * if (map.containsKey(key)) {
198 jsr166 1.36 * return map.put(key, value);
199 dl 1.55 * } else
200     * return null;
201     * }</pre>
202 jsr166 1.36 *
203 dl 1.15 * except that the action is performed atomically.
204 jsr166 1.21 *
205 dl 1.55 * @implNote This implementation intentionally re-abstracts the
206     * inappropriate default provided in {@code Map}.
207 dl 1.46 *
208 jsr166 1.24 * @param key key with which the specified value is associated
209     * @param value value to be associated with the specified key
210 jsr166 1.25 * @return the previous value associated with the specified key, or
211 jsr166 1.38 * {@code null} if there was no mapping for the key.
212     * (A {@code null} return can also indicate that the map
213     * previously associated {@code null} with the key,
214 jsr166 1.25 * if the implementation supports null values.)
215 jsr166 1.38 * @throws UnsupportedOperationException if the {@code put} operation
216 jsr166 1.24 * is not supported by this map
217 jsr166 1.25 * @throws ClassCastException if the class of the specified key or value
218     * prevents it from being stored in this map
219 jsr166 1.24 * @throws NullPointerException if the specified key or value is null,
220     * and this map does not permit null keys or values
221 jsr166 1.25 * @throws IllegalArgumentException if some property of the specified key
222     * or value prevents it from being stored in this map
223 dl 1.15 */
224 dl 1.16 V replace(K key, V value);
225 dl 1.44
226     /**
227     * {@inheritDoc}
228     *
229 dl 1.46 * @implSpec
230     * <p>The default implementation is equivalent to, for this {@code map}:
231 jsr166 1.52 * <pre> {@code
232 dl 1.55 * for ((Map.Entry<K, V> entry : map.entrySet())
233     * do {
234     * K k = entry.getKey();
235     * V v = entry.getValue();
236     * } while(!replace(k, v, function.apply(k, v)));
237     * }</pre>
238 dl 1.46 *
239     * The default implementation may retry these steps when multiple
240 dl 1.55 * threads attempt updates including potentially calling the function
241     * repeatedly for a given key.
242     *
243     * <p>This implementation assumes that the ConcurrentMap cannot contain null
244     * values and {@code get()} returning null unambiguously means the key is
245     * absent. Implementations which support null values <strong>must</strong>
246     * override this default implementation.
247 dl 1.46 *
248     * @throws UnsupportedOperationException {@inheritDoc}
249     * @throws NullPointerException {@inheritDoc}
250     * @throws ClassCastException {@inheritDoc}
251     * @throws IllegalArgumentException {@inheritDoc}
252     * @since 1.8
253 dl 1.44 */
254     @Override
255     default void replaceAll(BiFunction<? super K, ? super V, ? extends V> function) {
256 dl 1.46 Objects.requireNonNull(function);
257     forEach((k,v) -> {
258 dl 1.55 while(!replace(k, v, function.apply(k, v))) {
259 dl 1.46 // v changed or k is gone
260     if ( (v = get(k)) == null) {
261     // k is no longer in the map.
262     break;
263     }
264 dl 1.44 }
265 dl 1.46 });
266     }
267    
268     /**
269     * {@inheritDoc}
270     *
271     * @implSpec
272     * The default implementation is equivalent to the following steps for this
273     * {@code map}, then returning the current value or {@code null} if now
274     * absent:
275     *
276 jsr166 1.52 * <pre> {@code
277 dl 1.46 * if (map.get(key) == null) {
278 dl 1.55 * V newValue = mappingFunction.apply(key);
279     * if (newValue != null)
280     * return map.putIfAbsent(key, newValue);
281     * }
282     * }</pre>
283 dl 1.46 *
284     * The default implementation may retry these steps when multiple
285 dl 1.55 * threads attempt updates including potentially calling the mapping
286     * function multiple times.
287     *
288     * <p>This implementation assumes that the ConcurrentMap cannot contain null
289     * values and {@code get()} returning null unambiguously means the key is
290     * absent. Implementations which support null values <strong>must</strong>
291     * override this default implementation.
292 dl 1.46 *
293     * @throws UnsupportedOperationException {@inheritDoc}
294     * @throws ClassCastException {@inheritDoc}
295     * @throws NullPointerException {@inheritDoc}
296     * @since 1.8
297     */
298     @Override
299     default V computeIfAbsent(K key,
300     Function<? super K, ? extends V> mappingFunction) {
301     Objects.requireNonNull(mappingFunction);
302     V v, newValue;
303     return ((v = get(key)) == null &&
304     (newValue = mappingFunction.apply(key)) != null &&
305     (v = putIfAbsent(key, newValue)) == null) ? newValue : v;
306     }
307 dl 1.44
308 dl 1.46 /**
309     * {@inheritDoc}
310     *
311     * @implSpec
312     * The default implementation is equivalent to performing the following
313     * steps for this {@code map}, then returning the current value or
314 dl 1.55 * {@code null} if now absent. :
315 dl 1.46 *
316 jsr166 1.52 * <pre> {@code
317 dl 1.46 * if (map.get(key) != null) {
318 dl 1.55 * V oldValue = map.get(key);
319     * V newValue = remappingFunction.apply(key, oldValue);
320     * if (newValue != null)
321     * map.replace(key, oldValue, newValue);
322     * else
323     * map.remove(key, oldValue);
324     * }
325     * }</pre>
326 dl 1.46 *
327 dl 1.55 * The default implementation may retry these steps when multiple threads
328     * attempt updates including potentially calling the remapping function
329 dl 1.46 * multiple times.
330     *
331 dl 1.55 * <p>This implementation assumes that the ConcurrentMap cannot contain null
332     * values and {@code get()} returning null unambiguously means the key is
333     * absent. Implementations which support null values <strong>must</strong>
334     * override this default implementation.
335     *
336 dl 1.46 * @throws UnsupportedOperationException {@inheritDoc}
337     * @throws ClassCastException {@inheritDoc}
338     * @throws NullPointerException {@inheritDoc}
339     * @since 1.8
340     */
341     @Override
342     default V computeIfPresent(K key,
343     BiFunction<? super K, ? super V, ? extends V> remappingFunction) {
344     Objects.requireNonNull(remappingFunction);
345     V oldValue;
346 dl 1.55 while((oldValue = get(key)) != null) {
347 dl 1.46 V newValue = remappingFunction.apply(key, oldValue);
348     if (newValue != null) {
349     if (replace(key, oldValue, newValue))
350     return newValue;
351     } else if (remove(key, oldValue))
352 dl 1.55 return null;
353 dl 1.46 }
354     return oldValue;
355     }
356    
357     /**
358     * {@inheritDoc}
359     *
360     * @implSpec
361     * The default implementation is equivalent to performing the following
362     * steps for this {@code map}, then returning the current value or
363     * {@code null} if absent:
364     *
365 jsr166 1.52 * <pre> {@code
366 dl 1.46 * V oldValue = map.get(key);
367     * V newValue = remappingFunction.apply(key, oldValue);
368     * if (oldValue != null ) {
369 dl 1.55 * if (newValue != null)
370     * map.replace(key, oldValue, newValue);
371     * else
372     * map.remove(key, oldValue);
373 dl 1.46 * } else {
374 dl 1.55 * if (newValue != null)
375     * map.putIfAbsent(key, newValue);
376     * else
377     * return null;
378     * }
379     * }</pre>
380 dl 1.46 *
381     * The default implementation may retry these steps when multiple
382 dl 1.55 * threads attempt updates including potentially calling the remapping
383     * function multiple times.
384     *
385     * <p>This implementation assumes that the ConcurrentMap cannot contain null
386     * values and {@code get()} returning null unambiguously means the key is
387     * absent. Implementations which support null values <strong>must</strong>
388     * override this default implementation.
389 dl 1.46 *
390     * @throws UnsupportedOperationException {@inheritDoc}
391     * @throws ClassCastException {@inheritDoc}
392     * @throws NullPointerException {@inheritDoc}
393     * @since 1.8
394     */
395     @Override
396     default V compute(K key,
397     BiFunction<? super K, ? super V, ? extends V> remappingFunction) {
398     Objects.requireNonNull(remappingFunction);
399     V oldValue = get(key);
400 dl 1.55 for(;;) {
401 dl 1.46 V newValue = remappingFunction.apply(key, oldValue);
402     if (newValue == null) {
403     // delete mapping
404     if (oldValue != null || containsKey(key)) {
405     // something to remove
406     if (remove(key, oldValue)) {
407     // removed the old value as expected
408     return null;
409     }
410    
411     // some other value replaced old value. try again.
412     oldValue = get(key);
413     } else {
414     // nothing to do. Leave things as they were.
415     return null;
416     }
417     } else {
418     // add or replace old mapping
419     if (oldValue != null) {
420     // replace
421     if (replace(key, oldValue, newValue)) {
422     // replaced as expected.
423     return newValue;
424     }
425    
426     // some other value replaced old value. try again.
427     oldValue = get(key);
428     } else {
429     // add (replace if oldValue was null)
430     if ((oldValue = putIfAbsent(key, newValue)) == null) {
431     // replaced
432     return newValue;
433     }
434    
435     // some other value replaced old value. try again.
436     }
437 dl 1.44 }
438     }
439     }
440    
441 dl 1.55
442 dl 1.46 /**
443     * {@inheritDoc}
444     *
445     * @implSpec
446     * The default implementation is equivalent to performing the following
447     * steps for this {@code map}, then returning the current value or
448     * {@code null} if absent:
449     *
450 jsr166 1.52 * <pre> {@code
451 dl 1.46 * V oldValue = map.get(key);
452     * V newValue = (oldValue == null) ? value :
453 dl 1.55 * remappingFunction.apply(oldValue, value);
454 dl 1.46 * if (newValue == null)
455 dl 1.55 * map.remove(key);
456 dl 1.46 * else
457 dl 1.55 * map.put(key, newValue);
458     * }</pre>
459 dl 1.46 *
460 dl 1.55 * <p>The default implementation may retry these steps when multiple
461     * threads attempt updates including potentially calling the remapping
462     * function multiple times.
463     *
464     * <p>This implementation assumes that the ConcurrentMap cannot contain null
465     * values and {@code get()} returning null unambiguously means the key is
466     * absent. Implementations which support null values <strong>must</strong>
467     * override this default implementation.
468 dl 1.46 *
469     * @throws UnsupportedOperationException {@inheritDoc}
470     * @throws ClassCastException {@inheritDoc}
471     * @throws NullPointerException {@inheritDoc}
472     * @since 1.8
473     */
474     @Override
475     default V merge(K key, V value,
476     BiFunction<? super V, ? super V, ? extends V> remappingFunction) {
477     Objects.requireNonNull(remappingFunction);
478     Objects.requireNonNull(value);
479     V oldValue = get(key);
480     for (;;) {
481     if (oldValue != null) {
482     V newValue = remappingFunction.apply(oldValue, value);
483     if (newValue != null) {
484     if (replace(key, oldValue, newValue))
485     return newValue;
486     } else if (remove(key, oldValue)) {
487     return null;
488     }
489     oldValue = get(key);
490     } else {
491     if ((oldValue = putIfAbsent(key, value)) == null) {
492     return value;
493     }
494     }
495     }
496     }
497 tim 1.1 }