ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/jsr166/jsr166/src/main/java/util/concurrent/ConcurrentMap.java
Revision: 1.52
Committed: Mon Dec 9 17:00:23 2013 UTC (10 years, 6 months ago) by jsr166
Branch: MAIN
Changes since 1.51: +20 -24 lines
Log Message:
use the one true code snippet 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     import java.util.Map;
9 dl 1.46 import java.util.Objects;
10     import java.util.function.BiConsumer;
11 dl 1.44 import java.util.function.BiFunction;
12 dl 1.46 import java.util.function.Function;
13 tim 1.1
14     /**
15 jsr166 1.43 * A {@link java.util.Map} providing thread safety and atomicity
16 dl 1.42 * guarantees.
17 dl 1.19 *
18 dl 1.46 * <p>To support atomic usages, ConcurrentMaps are expected not to
19     * allow {@code null} as a legal value (and to throw exceptions upon
20     * attempted insertions). This enables a return value of {@code null}
21     * to unambiguously indicate the absence of a mapping. This interface
22     * does not strictly forbid implementations that may hold {@code null}
23     * values. However, in any that do so, a {@code null} value must bear
24     * the same interpretation as the absence of a mapping in order to
25     * conform to method atomicity requirements. Further, any that do so
26     * must override all default method implementations.
27     *
28     * <p>Several methods (for example {@link #putIfAbsent}) inherited
29     * from {@link Map} do not have default implementations, and so must
30     * be provided by implementations of this interface, even though they
31     * have (non-atomic) default implementations in the {@link Map}
32     * interface.
33     *
34 jsr166 1.29 * <p>Memory consistency effects: As with other concurrent
35     * collections, actions in a thread prior to placing an object into a
36     * {@code ConcurrentMap} as a key or value
37     * <a href="package-summary.html#MemoryVisibility"><i>happen-before</i></a>
38     * actions subsequent to the access or removal of that object from
39     * the {@code ConcurrentMap} in another thread.
40     *
41 dl 1.19 * <p>This interface is a member of the
42 jsr166 1.30 * <a href="{@docRoot}/../technotes/guides/collections/index.html">
43 jsr166 1.47 * Java Collections Framework</a>.
44 jsr166 1.21 *
45 dl 1.4 * @since 1.5
46     * @author Doug Lea
47 dl 1.13 * @param <K> the type of keys maintained by this map
48 jsr166 1.21 * @param <V> the type of mapped values
49 dl 1.4 */
50 jsr166 1.47 public interface ConcurrentMap<K,V> extends Map<K,V> {
51 dl 1.41
52     /**
53     * {@inheritDoc}
54     *
55 dl 1.46 * @implNote The default implementation returns the result of
56     * {@code get(key)} unless {@code null}, in which case it returns
57     * the given defaultValue.
58     *
59     * @throws ClassCastException {@inheritDoc}
60     * @throws NullPointerException {@inheritDoc}
61     * @since 1.8
62 dl 1.41 */
63     @Override
64     default V getOrDefault(Object key, V defaultValue) {
65     V v;
66     return ((v = get(key)) != null) ? v : defaultValue;
67     }
68    
69 dl 1.46 /**
70     * {@inheritDoc}
71     *
72     * @implSpec The default implementation is equivalent to, for this
73     * {@code map}:
74 jsr166 1.52 * <pre> {@code
75 jsr166 1.49 * for (Map.Entry<K,V> entry : map.entrySet())
76 jsr166 1.52 * action.accept(entry.getKey(), entry.getValue());}</pre>
77 dl 1.46 *
78     * @implNote The default implementation assumes that {@code
79     * IllegalStateException} thrown by {@code getKey()} or {@code
80     * getValue()} indicates that the entry no longer exists.
81     * Operation continues for subsequent entries.
82     *
83     * @throws NullPointerException {@inheritDoc}
84     * @since 1.8
85     */
86     @Override
87     default void forEach(BiConsumer<? super K, ? super V> action) {
88     Objects.requireNonNull(action);
89 jsr166 1.47 for (Map.Entry<K,V> entry : entrySet()) {
90 dl 1.46 K k;
91     V v;
92     try {
93     k = entry.getKey();
94     v = entry.getValue();
95 jsr166 1.47 } catch (IllegalStateException ise) {
96 dl 1.46 // this usually means the entry is no longer in the map.
97     continue;
98     }
99     action.accept(k, v);
100     }
101     }
102    
103 tim 1.1 /**
104     * If the specified key is not already associated
105 dl 1.46 * with a value, associates it with the given value.
106 jsr166 1.51 * This is equivalent to, for this {@code map}:
107 jsr166 1.52 * <pre> {@code
108 jsr166 1.48 * if (map.containsKey(key))
109     * return map.get(key);
110     * else
111 jsr166 1.52 * return map.put(key, value);}</pre>
112 jsr166 1.36 *
113 jsr166 1.21 * except that the action is performed atomically.
114     *
115 dl 1.46 * @implNote There is no default implementation.
116     *
117 jsr166 1.24 * @param key key with which the specified value is to be associated
118     * @param value value to be associated with the specified key
119 jsr166 1.25 * @return the previous value associated with the specified key, or
120 jsr166 1.38 * {@code null} if there was no mapping for the key.
121     * (A {@code null} return can also indicate that the map
122     * previously associated {@code null} with the key,
123 jsr166 1.25 * if the implementation supports null values.)
124 jsr166 1.38 * @throws UnsupportedOperationException if the {@code put} operation
125 jsr166 1.24 * is not supported by this map
126 tim 1.1 * @throws ClassCastException if the class of the specified key or value
127 jsr166 1.24 * prevents it from being stored in this map
128     * @throws NullPointerException if the specified key or value is null,
129     * and this map does not permit null keys or values
130     * @throws IllegalArgumentException if some property of the specified key
131     * or value prevents it from being stored in this map
132 dl 1.18 */
133 jsr166 1.47 V putIfAbsent(K key, V value);
134 dl 1.6
135     /**
136 jsr166 1.21 * Removes the entry for a key only if currently mapped to a given value.
137 jsr166 1.51 * This is equivalent to, for this {@code map}:
138 jsr166 1.52 * <pre> {@code
139     * if (map.containsKey(key)
140     * && Objects.equals(map.get(key), value)) {
141 jsr166 1.36 * map.remove(key);
142     * return true;
143     * } else
144 jsr166 1.52 * return false;}</pre>
145 jsr166 1.36 *
146 dl 1.6 * except that the action is performed atomically.
147 jsr166 1.21 *
148 dl 1.46 * @implNote There is no default implementation.
149     *
150 jsr166 1.24 * @param key key with which the specified value is associated
151 jsr166 1.25 * @param value value expected to be associated with the specified key
152 jsr166 1.38 * @return {@code true} if the value was removed
153     * @throws UnsupportedOperationException if the {@code remove} operation
154 jsr166 1.24 * is not supported by this map
155 jsr166 1.25 * @throws ClassCastException if the key or value is of an inappropriate
156 jsr166 1.35 * type for this map
157 dl 1.33 * (<a href="../Collection.html#optional-restrictions">optional</a>)
158 jsr166 1.24 * @throws NullPointerException if the specified key or value is null,
159 dl 1.32 * and this map does not permit null keys or values
160 dl 1.33 * (<a href="../Collection.html#optional-restrictions">optional</a>)
161 dl 1.6 */
162 dl 1.7 boolean remove(Object key, Object value);
163 dl 1.14
164     /**
165 jsr166 1.21 * Replaces the entry for a key only if currently mapped to a given value.
166 jsr166 1.51 * This is equivalent to, for this {@code map}:
167 jsr166 1.52 * <pre> {@code
168     * if (map.containsKey(key)
169     * && Objects.equals(map.get(key), oldValue)) {
170 jsr166 1.36 * map.put(key, newValue);
171     * return true;
172     * } else
173 jsr166 1.52 * return false;}</pre>
174 jsr166 1.36 *
175 dl 1.14 * except that the action is performed atomically.
176 jsr166 1.21 *
177 dl 1.46 * @implNote There is no default implementation.
178     *
179 jsr166 1.24 * @param key key with which the specified value is associated
180     * @param oldValue value expected to be associated with the specified key
181     * @param newValue value to be associated with the specified key
182 jsr166 1.38 * @return {@code true} if the value was replaced
183     * @throws UnsupportedOperationException if the {@code put} operation
184 jsr166 1.24 * is not supported by this map
185 jsr166 1.25 * @throws ClassCastException if the class of a specified key or value
186     * prevents it from being stored in this map
187 jsr166 1.24 * @throws NullPointerException if a specified key or value is null,
188     * and this map does not permit null keys or values
189 jsr166 1.25 * @throws IllegalArgumentException if some property of a specified key
190     * or value prevents it from being stored in this map
191 dl 1.14 */
192     boolean replace(K key, V oldValue, V newValue);
193 dl 1.6
194 dl 1.15 /**
195 jsr166 1.21 * Replaces the entry for a key only if currently mapped to some value.
196 jsr166 1.51 * This is equivalent to, for this {@code map}:
197 jsr166 1.52 * <pre> {@code
198 jsr166 1.51 * if (map.containsKey(key))
199 jsr166 1.36 * return map.put(key, value);
200 jsr166 1.51 * else
201 jsr166 1.52 * return null;}</pre>
202 jsr166 1.36 *
203 dl 1.15 * except that the action is performed atomically.
204 jsr166 1.21 *
205 dl 1.46 * @implNote There is no default implementation.
206     *
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.50 * for (Map.Entry<K,V> entry : map.entrySet()) {
232     * K k;
233     * V v;
234     * do {
235     * k = entry.getKey();
236     * v = entry.getValue();
237     * } while (!map.replace(k, v, function.apply(k, v)));
238 jsr166 1.51 * }}</pre>
239 dl 1.46 *
240     * The default implementation may retry these steps when multiple
241     * threads attempt updates, and may call the function multiple
242     * times.
243     *
244     * @throws UnsupportedOperationException {@inheritDoc}
245     * @throws NullPointerException {@inheritDoc}
246     * @throws ClassCastException {@inheritDoc}
247     * @throws IllegalArgumentException {@inheritDoc}
248     * @since 1.8
249 dl 1.44 */
250     @Override
251     default void replaceAll(BiFunction<? super K, ? super V, ? extends V> function) {
252 dl 1.46 Objects.requireNonNull(function);
253     forEach((k,v) -> {
254 jsr166 1.47 while (!replace(k, v, function.apply(k, v))) {
255 dl 1.46 // v changed or k is gone
256     if ( (v = get(k)) == null) {
257     // k is no longer in the map.
258     break;
259     }
260 dl 1.44 }
261 dl 1.46 });
262     }
263    
264     /**
265     * {@inheritDoc}
266     *
267     * @implSpec
268     * The default implementation is equivalent to the following steps for this
269     * {@code map}, then returning the current value or {@code null} if now
270     * absent:
271     *
272 jsr166 1.52 * <pre> {@code
273 dl 1.46 * if (map.get(key) == null) {
274 jsr166 1.51 * V newValue = mappingFunction.apply(key);
275     * if (newValue != null)
276     * return map.putIfAbsent(key, newValue);
277     * }}</pre>
278 dl 1.46 *
279     * The default implementation may retry these steps when multiple
280     * threads attempt updates, and may call the mapping function
281     * multiple times.
282     *
283     * @throws UnsupportedOperationException {@inheritDoc}
284     * @throws ClassCastException {@inheritDoc}
285     * @throws NullPointerException {@inheritDoc}
286     * @since 1.8
287     */
288     @Override
289     default V computeIfAbsent(K key,
290     Function<? super K, ? extends V> mappingFunction) {
291     Objects.requireNonNull(mappingFunction);
292     V v, newValue;
293     return ((v = get(key)) == null &&
294     (newValue = mappingFunction.apply(key)) != null &&
295     (v = putIfAbsent(key, newValue)) == null) ? newValue : v;
296     }
297 dl 1.44
298 dl 1.46 /**
299     * {@inheritDoc}
300     *
301     * @implSpec
302     * The default implementation is equivalent to performing the following
303     * steps for this {@code map}, then returning the current value or
304 jsr166 1.51 * {@code null} if now absent:
305 dl 1.46 *
306 jsr166 1.52 * <pre> {@code
307 dl 1.46 * if (map.get(key) != null) {
308 jsr166 1.51 * V oldValue = map.get(key);
309     * V newValue = remappingFunction.apply(key, oldValue);
310     * if (newValue != null)
311     * map.replace(key, oldValue, newValue);
312     * else
313     * map.remove(key, oldValue);
314     * }}</pre>
315 dl 1.46 *
316     * The default implementation may retry these steps when multiple
317     * threads attempt updates, and may call the remapping function
318     * multiple times.
319     *
320     * @throws UnsupportedOperationException {@inheritDoc}
321     * @throws ClassCastException {@inheritDoc}
322     * @throws NullPointerException {@inheritDoc}
323     * @since 1.8
324     */
325     @Override
326     default V computeIfPresent(K key,
327     BiFunction<? super K, ? super V, ? extends V> remappingFunction) {
328     Objects.requireNonNull(remappingFunction);
329     V oldValue;
330 jsr166 1.47 while ((oldValue = get(key)) != null) {
331 dl 1.46 V newValue = remappingFunction.apply(key, oldValue);
332     if (newValue != null) {
333     if (replace(key, oldValue, newValue))
334     return newValue;
335     } else if (remove(key, oldValue))
336     return null;
337     }
338     return oldValue;
339     }
340    
341     /**
342     * {@inheritDoc}
343     *
344     * @implSpec
345     * The default implementation is equivalent to performing the following
346     * steps for this {@code map}, then returning the current value or
347     * {@code null} if absent:
348     *
349 jsr166 1.52 * <pre> {@code
350 dl 1.46 * V oldValue = map.get(key);
351     * V newValue = remappingFunction.apply(key, oldValue);
352     * if (oldValue != null ) {
353 jsr166 1.51 * if (newValue != null)
354     * map.replace(key, oldValue, newValue);
355     * else
356     * map.remove(key, oldValue);
357 dl 1.46 * } else {
358 jsr166 1.51 * if (newValue != null)
359     * map.putIfAbsent(key, newValue);
360     * else
361     * return null;
362     * }}</pre>
363 dl 1.46 *
364     * The default implementation may retry these steps when multiple
365     * threads attempt updates, and may call the remapping function
366     * multiple times.
367     *
368     * @throws UnsupportedOperationException {@inheritDoc}
369     * @throws ClassCastException {@inheritDoc}
370     * @throws NullPointerException {@inheritDoc}
371     * @since 1.8
372     */
373     @Override
374     default V compute(K key,
375     BiFunction<? super K, ? super V, ? extends V> remappingFunction) {
376     Objects.requireNonNull(remappingFunction);
377     V oldValue = get(key);
378 jsr166 1.47 for (;;) {
379 dl 1.46 V newValue = remappingFunction.apply(key, oldValue);
380     if (newValue == null) {
381     // delete mapping
382     if (oldValue != null || containsKey(key)) {
383     // something to remove
384     if (remove(key, oldValue)) {
385     // removed the old value as expected
386     return null;
387     }
388    
389     // some other value replaced old value. try again.
390     oldValue = get(key);
391     } else {
392     // nothing to do. Leave things as they were.
393     return null;
394     }
395     } else {
396     // add or replace old mapping
397     if (oldValue != null) {
398     // replace
399     if (replace(key, oldValue, newValue)) {
400     // replaced as expected.
401     return newValue;
402     }
403    
404     // some other value replaced old value. try again.
405     oldValue = get(key);
406     } else {
407     // add (replace if oldValue was null)
408     if ((oldValue = putIfAbsent(key, newValue)) == null) {
409     // replaced
410     return newValue;
411     }
412    
413     // some other value replaced old value. try again.
414     }
415 dl 1.44 }
416     }
417     }
418    
419 dl 1.46 /**
420     * {@inheritDoc}
421     *
422     * @implSpec
423     * The default implementation is equivalent to performing the following
424     * steps for this {@code map}, then returning the current value or
425     * {@code null} if absent:
426     *
427 jsr166 1.52 * <pre> {@code
428 dl 1.46 * V oldValue = map.get(key);
429     * V newValue = (oldValue == null) ? value :
430 jsr166 1.51 * remappingFunction.apply(oldValue, value);
431 dl 1.46 * if (newValue == null)
432 jsr166 1.51 * map.remove(key);
433 dl 1.46 * else
434 jsr166 1.52 * map.put(key, newValue);}</pre>
435 dl 1.46 *
436     * The default implementation may retry these steps when multiple
437     * threads attempt updates, and may call the remapping function
438     * multiple times.
439     *
440     * @throws UnsupportedOperationException {@inheritDoc}
441     * @throws ClassCastException {@inheritDoc}
442     * @throws NullPointerException {@inheritDoc}
443     * @since 1.8
444     */
445     @Override
446     default V merge(K key, V value,
447     BiFunction<? super V, ? super V, ? extends V> remappingFunction) {
448     Objects.requireNonNull(remappingFunction);
449     Objects.requireNonNull(value);
450     V oldValue = get(key);
451     for (;;) {
452     if (oldValue != null) {
453     V newValue = remappingFunction.apply(oldValue, value);
454     if (newValue != null) {
455     if (replace(key, oldValue, newValue))
456     return newValue;
457     } else if (remove(key, oldValue)) {
458     return null;
459     }
460     oldValue = get(key);
461     } else {
462     if ((oldValue = putIfAbsent(key, value)) == null) {
463     return value;
464     }
465     }
466     }
467     }
468 tim 1.1 }