ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/jsr166/jsr166/src/main/java/util/concurrent/ConcurrentMap.java
Revision: 1.51
Committed: Sat Dec 7 17:59:40 2013 UTC (10 years, 5 months ago) by jsr166
Branch: MAIN
Changes since 1.50: +37 -41 lines
Log Message:
use consistent code snippet formatting

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.51 * <pre> {@code
75 jsr166 1.49 * for (Map.Entry<K,V> entry : map.entrySet())
76 jsr166 1.48 * action.accept(entry.getKey(), entry.getValue());
77 dl 1.46 * }</pre>
78     *
79     * @implNote The default implementation assumes that {@code
80     * IllegalStateException} thrown by {@code getKey()} or {@code
81     * getValue()} indicates that the entry no longer exists.
82     * Operation continues for subsequent entries.
83     *
84     * @throws NullPointerException {@inheritDoc}
85     * @since 1.8
86     */
87     @Override
88     default void forEach(BiConsumer<? super K, ? super V> action) {
89     Objects.requireNonNull(action);
90 jsr166 1.47 for (Map.Entry<K,V> entry : entrySet()) {
91 dl 1.46 K k;
92     V v;
93     try {
94     k = entry.getKey();
95     v = entry.getValue();
96 jsr166 1.47 } catch (IllegalStateException ise) {
97 dl 1.46 // this usually means the entry is no longer in the map.
98     continue;
99     }
100     action.accept(k, v);
101     }
102     }
103    
104 tim 1.1 /**
105     * If the specified key is not already associated
106 dl 1.46 * with a value, associates it with the given value.
107 jsr166 1.51 * This is equivalent to, for this {@code map}:
108 jsr166 1.36 * <pre> {@code
109 jsr166 1.48 * if (map.containsKey(key))
110     * return map.get(key);
111     * else
112 jsr166 1.36 * return map.put(key, value);
113 dl 1.46 * }</pre>
114 jsr166 1.36 *
115 jsr166 1.21 * except that the action is performed atomically.
116     *
117 dl 1.46 * @implNote There is no default implementation.
118     *
119 jsr166 1.24 * @param key key with which the specified value is to be associated
120     * @param value value to be associated with the specified key
121 jsr166 1.25 * @return the previous value associated with the specified key, or
122 jsr166 1.38 * {@code null} if there was no mapping for the key.
123     * (A {@code null} return can also indicate that the map
124     * previously associated {@code null} with the key,
125 jsr166 1.25 * if the implementation supports null values.)
126 jsr166 1.38 * @throws UnsupportedOperationException if the {@code put} operation
127 jsr166 1.24 * is not supported by this map
128 tim 1.1 * @throws ClassCastException if the class of the specified key or value
129 jsr166 1.24 * prevents it from being stored in this map
130     * @throws NullPointerException if the specified key or value is null,
131     * and this map does not permit null keys or values
132     * @throws IllegalArgumentException if some property of the specified key
133     * or value prevents it from being stored in this map
134 dl 1.18 */
135 jsr166 1.47 V putIfAbsent(K key, V value);
136 dl 1.6
137     /**
138 jsr166 1.21 * Removes the entry for a key only if currently mapped to a given value.
139 jsr166 1.51 * This is equivalent to, for this {@code map}:
140 jsr166 1.36 * <pre> {@code
141 dl 1.40 * if (map.containsKey(key) && Objects.equals(map.get(key), value)) {
142 jsr166 1.36 * map.remove(key);
143     * return true;
144     * } else
145 dl 1.46 * return false;
146     * }</pre>
147 jsr166 1.36 *
148 dl 1.6 * except that the action is performed atomically.
149 jsr166 1.21 *
150 dl 1.46 * @implNote There is no default implementation.
151     *
152 jsr166 1.24 * @param key key with which the specified value is associated
153 jsr166 1.25 * @param value value expected to be associated with the specified key
154 jsr166 1.38 * @return {@code true} if the value was removed
155     * @throws UnsupportedOperationException if the {@code remove} operation
156 jsr166 1.24 * is not supported by this map
157 jsr166 1.25 * @throws ClassCastException if the key or value is of an inappropriate
158 jsr166 1.35 * type for this map
159 dl 1.33 * (<a href="../Collection.html#optional-restrictions">optional</a>)
160 jsr166 1.24 * @throws NullPointerException if the specified key or value is null,
161 dl 1.32 * and this map does not permit null keys or values
162 dl 1.33 * (<a href="../Collection.html#optional-restrictions">optional</a>)
163 dl 1.6 */
164 dl 1.7 boolean remove(Object key, Object value);
165 dl 1.14
166     /**
167 jsr166 1.21 * Replaces the entry for a key only if currently mapped to a given value.
168 jsr166 1.51 * This is equivalent to, for this {@code map}:
169 jsr166 1.36 * <pre> {@code
170 dl 1.40 * if (map.containsKey(key) && Objects.equals(map.get(key), oldValue)) {
171 jsr166 1.36 * map.put(key, newValue);
172     * return true;
173     * } else
174 dl 1.46 * return false;
175     * }</pre>
176 jsr166 1.36 *
177 dl 1.14 * except that the action is performed atomically.
178 jsr166 1.21 *
179 dl 1.46 * @implNote There is no default implementation.
180     *
181 jsr166 1.24 * @param key key with which the specified value is associated
182     * @param oldValue value expected to be associated with the specified key
183     * @param newValue value to be associated with the specified key
184 jsr166 1.38 * @return {@code true} if the value was replaced
185     * @throws UnsupportedOperationException if the {@code put} operation
186 jsr166 1.24 * is not supported by this map
187 jsr166 1.25 * @throws ClassCastException if the class of a specified key or value
188     * prevents it from being stored in this map
189 jsr166 1.24 * @throws NullPointerException if a specified key or value is null,
190     * and this map does not permit null keys or values
191 jsr166 1.25 * @throws IllegalArgumentException if some property of a specified key
192     * or value prevents it from being stored in this map
193 dl 1.14 */
194     boolean replace(K key, V oldValue, V newValue);
195 dl 1.6
196 dl 1.15 /**
197 jsr166 1.21 * Replaces the entry for a key only if currently mapped to some value.
198 jsr166 1.51 * This is equivalent to, for this {@code map}:
199 jsr166 1.36 * <pre> {@code
200 jsr166 1.51 * if (map.containsKey(key))
201 jsr166 1.36 * return map.put(key, value);
202 jsr166 1.51 * else
203 dl 1.46 * return null;
204     * }</pre>
205 jsr166 1.36 *
206 dl 1.15 * except that the action is performed atomically.
207 jsr166 1.21 *
208 dl 1.46 * @implNote There is no default implementation.
209     *
210 jsr166 1.24 * @param key key with which the specified value is associated
211     * @param value value to be associated with the specified key
212 jsr166 1.25 * @return the previous value associated with the specified key, or
213 jsr166 1.38 * {@code null} if there was no mapping for the key.
214     * (A {@code null} return can also indicate that the map
215     * previously associated {@code null} with the key,
216 jsr166 1.25 * if the implementation supports null values.)
217 jsr166 1.38 * @throws UnsupportedOperationException if the {@code put} operation
218 jsr166 1.24 * is not supported by this map
219 jsr166 1.25 * @throws ClassCastException if the class of the specified key or value
220     * prevents it from being stored in this map
221 jsr166 1.24 * @throws NullPointerException if the specified key or value is null,
222     * and this map does not permit null keys or values
223 jsr166 1.25 * @throws IllegalArgumentException if some property of the specified key
224     * or value prevents it from being stored in this map
225 dl 1.15 */
226 dl 1.16 V replace(K key, V value);
227 dl 1.44
228     /**
229     * {@inheritDoc}
230     *
231 dl 1.46 * @implSpec
232     * <p>The default implementation is equivalent to, for this {@code map}:
233 jsr166 1.51 * <pre> {@code
234 jsr166 1.50 * for (Map.Entry<K,V> entry : map.entrySet()) {
235     * K k;
236     * V v;
237     * do {
238     * k = entry.getKey();
239     * v = entry.getValue();
240     * } while (!map.replace(k, v, function.apply(k, v)));
241 jsr166 1.51 * }}</pre>
242 dl 1.46 *
243     * The default implementation may retry these steps when multiple
244     * threads attempt updates, and may call the function multiple
245     * times.
246     *
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.47 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.51 * <pre> {@code
276 dl 1.46 * if (map.get(key) == null) {
277 jsr166 1.51 * 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     * threads attempt updates, and may call the mapping function
284     * multiple times.
285     *
286     * @throws UnsupportedOperationException {@inheritDoc}
287     * @throws ClassCastException {@inheritDoc}
288     * @throws NullPointerException {@inheritDoc}
289     * @since 1.8
290     */
291     @Override
292     default V computeIfAbsent(K key,
293     Function<? super K, ? extends V> mappingFunction) {
294     Objects.requireNonNull(mappingFunction);
295     V v, newValue;
296     return ((v = get(key)) == null &&
297     (newValue = mappingFunction.apply(key)) != null &&
298     (v = putIfAbsent(key, newValue)) == null) ? newValue : v;
299     }
300 dl 1.44
301 dl 1.46 /**
302     * {@inheritDoc}
303     *
304     * @implSpec
305     * The default implementation is equivalent to performing the following
306     * steps for this {@code map}, then returning the current value or
307 jsr166 1.51 * {@code null} if now absent:
308 dl 1.46 *
309 jsr166 1.51 * <pre> {@code
310 dl 1.46 * if (map.get(key) != null) {
311 jsr166 1.51 * V oldValue = map.get(key);
312     * V newValue = remappingFunction.apply(key, oldValue);
313     * if (newValue != null)
314     * map.replace(key, oldValue, newValue);
315     * else
316     * map.remove(key, oldValue);
317     * }}</pre>
318 dl 1.46 *
319     * The default implementation may retry these steps when multiple
320     * threads attempt updates, and may call the remapping function
321     * multiple times.
322     *
323     * @throws UnsupportedOperationException {@inheritDoc}
324     * @throws ClassCastException {@inheritDoc}
325     * @throws NullPointerException {@inheritDoc}
326     * @since 1.8
327     */
328     @Override
329     default V computeIfPresent(K key,
330     BiFunction<? super K, ? super V, ? extends V> remappingFunction) {
331     Objects.requireNonNull(remappingFunction);
332     V oldValue;
333 jsr166 1.47 while ((oldValue = get(key)) != null) {
334 dl 1.46 V newValue = remappingFunction.apply(key, oldValue);
335     if (newValue != null) {
336     if (replace(key, oldValue, newValue))
337     return newValue;
338     } else if (remove(key, oldValue))
339     return null;
340     }
341     return oldValue;
342     }
343    
344     /**
345     * {@inheritDoc}
346     *
347     * @implSpec
348     * The default implementation is equivalent to performing the following
349     * steps for this {@code map}, then returning the current value or
350     * {@code null} if absent:
351     *
352 jsr166 1.51 * <pre> {@code
353 dl 1.46 * V oldValue = map.get(key);
354     * V newValue = remappingFunction.apply(key, oldValue);
355     * if (oldValue != null ) {
356 jsr166 1.51 * if (newValue != null)
357     * map.replace(key, oldValue, newValue);
358     * else
359     * map.remove(key, oldValue);
360 dl 1.46 * } else {
361 jsr166 1.51 * if (newValue != null)
362     * map.putIfAbsent(key, newValue);
363     * else
364     * return null;
365     * }}</pre>
366 dl 1.46 *
367     * The default implementation may retry these steps when multiple
368     * threads attempt updates, and may call the remapping function
369     * multiple times.
370     *
371     * @throws UnsupportedOperationException {@inheritDoc}
372     * @throws ClassCastException {@inheritDoc}
373     * @throws NullPointerException {@inheritDoc}
374     * @since 1.8
375     */
376     @Override
377     default V compute(K key,
378     BiFunction<? super K, ? super V, ? extends V> remappingFunction) {
379     Objects.requireNonNull(remappingFunction);
380     V oldValue = get(key);
381 jsr166 1.47 for (;;) {
382 dl 1.46 V newValue = remappingFunction.apply(key, oldValue);
383     if (newValue == null) {
384     // delete mapping
385     if (oldValue != null || containsKey(key)) {
386     // something to remove
387     if (remove(key, oldValue)) {
388     // removed the old value as expected
389     return null;
390     }
391    
392     // some other value replaced old value. try again.
393     oldValue = get(key);
394     } else {
395     // nothing to do. Leave things as they were.
396     return null;
397     }
398     } else {
399     // add or replace old mapping
400     if (oldValue != null) {
401     // replace
402     if (replace(key, oldValue, newValue)) {
403     // replaced as expected.
404     return newValue;
405     }
406    
407     // some other value replaced old value. try again.
408     oldValue = get(key);
409     } else {
410     // add (replace if oldValue was null)
411     if ((oldValue = putIfAbsent(key, newValue)) == null) {
412     // replaced
413     return newValue;
414     }
415    
416     // some other value replaced old value. try again.
417     }
418 dl 1.44 }
419     }
420     }
421    
422 dl 1.46 /**
423     * {@inheritDoc}
424     *
425     * @implSpec
426     * The default implementation is equivalent to performing the following
427     * steps for this {@code map}, then returning the current value or
428     * {@code null} if absent:
429     *
430 jsr166 1.51 * <pre> {@code
431 dl 1.46 * V oldValue = map.get(key);
432     * V newValue = (oldValue == null) ? value :
433 jsr166 1.51 * remappingFunction.apply(oldValue, value);
434 dl 1.46 * if (newValue == null)
435 jsr166 1.51 * map.remove(key);
436 dl 1.46 * else
437 jsr166 1.51 * map.put(key, newValue);
438 dl 1.46 * }</pre>
439     *
440     * The default implementation may retry these steps when multiple
441     * threads attempt updates, and may call the remapping function
442     * multiple times.
443     *
444     * @throws UnsupportedOperationException {@inheritDoc}
445     * @throws ClassCastException {@inheritDoc}
446     * @throws NullPointerException {@inheritDoc}
447     * @since 1.8
448     */
449     @Override
450     default V merge(K key, V value,
451     BiFunction<? super V, ? super V, ? extends V> remappingFunction) {
452     Objects.requireNonNull(remappingFunction);
453     Objects.requireNonNull(value);
454     V oldValue = get(key);
455     for (;;) {
456     if (oldValue != null) {
457     V newValue = remappingFunction.apply(oldValue, value);
458     if (newValue != null) {
459     if (replace(key, oldValue, newValue))
460     return newValue;
461     } else if (remove(key, oldValue)) {
462     return null;
463     }
464     oldValue = get(key);
465     } else {
466     if ((oldValue = putIfAbsent(key, value)) == null) {
467     return value;
468     }
469     }
470     }
471     }
472 tim 1.1 }