ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/jsr166/jsr166/src/main/java/util/concurrent/ConcurrentMap.java
Revision: 1.56
Committed: Wed Apr 29 18:01:41 2015 UTC (9 years, 1 month ago) by jsr166
Branch: MAIN
Changes since 1.55: +13 -13 lines
Log Message:
jsr166 coding style

File Contents

# Content
1 /*
2 * Written by Doug Lea with assistance from members of JCP JSR-166
3 * Expert Group and released to the public domain, as explained at
4 * http://creativecommons.org/publicdomain/zero/1.0/
5 */
6
7 package java.util.concurrent;
8
9 import java.util.Map;
10 import java.util.Objects;
11 import java.util.function.BiConsumer;
12 import java.util.function.BiFunction;
13 import java.util.function.Function;
14
15 /**
16 * A {@link java.util.Map} providing thread safety and atomicity
17 * guarantees.
18 *
19 * <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 *
27 * <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 * <p>This interface is a member of the
35 * <a href="{@docRoot}/../technotes/guides/collections/index.html">
36 * Java Collections Framework</a>.
37 *
38 * @since 1.5
39 * @author Doug Lea
40 * @param <K> the type of keys maintained by this map
41 * @param <V> the type of mapped values
42 */
43 public interface ConcurrentMap<K,V> extends Map<K,V> {
44
45 /**
46 * {@inheritDoc}
47 *
48 * @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 *
53 * @throws ClassCastException {@inheritDoc}
54 * @throws NullPointerException {@inheritDoc}
55 * @since 1.8
56 */
57 @Override
58 default V getOrDefault(Object key, V defaultValue) {
59 V v;
60 return ((v = get(key)) != null) ? v : defaultValue;
61 }
62
63 /**
64 * {@inheritDoc}
65 *
66 * @implSpec The default implementation is equivalent to, for this
67 * {@code map}:
68 * <pre> {@code
69 * 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 *
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 for (Map.Entry<K,V> entry : entrySet()) {
85 K k;
86 V v;
87 try {
88 k = entry.getKey();
89 v = entry.getValue();
90 } catch (IllegalStateException ise) {
91 // this usually means the entry is no longer in the map.
92 continue;
93 }
94 action.accept(k, v);
95 }
96 }
97
98 /**
99 * If the specified key is not already associated
100 * 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 * return map.get(key);
107 * }</pre>
108 *
109 * except that the action is performed atomically.
110 *
111 * @implNote This implementation intentionally re-abstracts the
112 * inappropriate default provided in {@code Map}.
113 *
114 * @param key key with which the specified value is to be associated
115 * @param value value to be associated with the specified key
116 * @return the previous value associated with the specified key, or
117 * {@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 * if the implementation supports null values.)
121 * @throws UnsupportedOperationException if the {@code put} operation
122 * is not supported by this map
123 * @throws ClassCastException if the class of the specified key or value
124 * 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 */
130 V putIfAbsent(K key, V value);
131
132 /**
133 * Removes the entry for a key only if currently mapped to a given value.
134 * This is equivalent to
135 * <pre> {@code
136 * if (map.containsKey(key) && Objects.equals(map.get(key), value)) {
137 * map.remove(key);
138 * return true;
139 * } else
140 * return false;
141 * }</pre>
142 *
143 * except that the action is performed atomically.
144 *
145 * @implNote This implementation intentionally re-abstracts the
146 * inappropriate default provided in {@code Map}.
147 *
148 * @param key key with which the specified value is associated
149 * @param value value expected to be associated with the specified key
150 * @return {@code true} if the value was removed
151 * @throws UnsupportedOperationException if the {@code remove} operation
152 * is not supported by this map
153 * @throws ClassCastException if the key or value is of an inappropriate
154 * type for this map
155 * (<a href="../Collection.html#optional-restrictions">optional</a>)
156 * @throws NullPointerException if the specified key or value is null,
157 * and this map does not permit null keys or values
158 * (<a href="../Collection.html#optional-restrictions">optional</a>)
159 */
160 boolean remove(Object key, Object value);
161
162 /**
163 * Replaces the entry for a key only if currently mapped to a given value.
164 * This is equivalent to
165 * <pre> {@code
166 * if (map.containsKey(key) && Objects.equals(map.get(key), oldValue)) {
167 * map.put(key, newValue);
168 * return true;
169 * } else
170 * return false;
171 * }</pre>
172 *
173 * except that the action is performed atomically.
174 *
175 * @implNote This implementation intentionally re-abstracts the
176 * inappropriate default provided in {@code Map}.
177 *
178 * @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 * @return {@code true} if the value was replaced
182 * @throws UnsupportedOperationException if the {@code put} operation
183 * is not supported by this map
184 * @throws ClassCastException if the class of a specified key or value
185 * prevents it from being stored in this map
186 * @throws NullPointerException if a specified key or value is null,
187 * and this map does not permit null keys or values
188 * @throws IllegalArgumentException if some property of a specified key
189 * or value prevents it from being stored in this map
190 */
191 boolean replace(K key, V oldValue, V newValue);
192
193 /**
194 * Replaces the entry for a key only if currently mapped to some value.
195 * This is equivalent to
196 * <pre> {@code
197 * if (map.containsKey(key)) {
198 * return map.put(key, value);
199 * } else
200 * return null;
201 * }</pre>
202 *
203 * except that the action is performed atomically.
204 *
205 * @implNote This implementation intentionally re-abstracts the
206 * inappropriate default provided in {@code Map}.
207 *
208 * @param key key with which the specified value is associated
209 * @param value value to be associated with the specified key
210 * @return the previous value associated with the specified key, or
211 * {@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 * if the implementation supports null values.)
215 * @throws UnsupportedOperationException if the {@code put} operation
216 * is not supported by this map
217 * @throws ClassCastException if the class of the specified key or value
218 * prevents it from being stored in this map
219 * @throws NullPointerException if the specified key or value is null,
220 * and this map does not permit null keys or values
221 * @throws IllegalArgumentException if some property of the specified key
222 * or value prevents it from being stored in this map
223 */
224 V replace(K key, V value);
225
226 /**
227 * {@inheritDoc}
228 *
229 * @implSpec
230 * <p>The default implementation is equivalent to, for this {@code map}:
231 * <pre> {@code
232 * 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 *
239 * The default implementation may retry these steps when multiple
240 * 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 *
248 * @throws UnsupportedOperationException {@inheritDoc}
249 * @throws NullPointerException {@inheritDoc}
250 * @throws ClassCastException {@inheritDoc}
251 * @throws IllegalArgumentException {@inheritDoc}
252 * @since 1.8
253 */
254 @Override
255 default void replaceAll(BiFunction<? super K, ? super V, ? extends V> function) {
256 Objects.requireNonNull(function);
257 forEach((k,v) -> {
258 while (!replace(k, v, function.apply(k, v))) {
259 // v changed or k is gone
260 if ( (v = get(k)) == null) {
261 // k is no longer in the map.
262 break;
263 }
264 }
265 });
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 * <pre> {@code
277 * if (map.get(key) == null) {
278 * V newValue = mappingFunction.apply(key);
279 * if (newValue != null)
280 * return map.putIfAbsent(key, newValue);
281 * }
282 * }</pre>
283 *
284 * The default implementation may retry these steps when multiple
285 * 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 *
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
308 /**
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 * {@code null} if now absent. :
315 *
316 * <pre> {@code
317 * if (map.get(key) != null) {
318 * 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 *
327 * The default implementation may retry these steps when multiple threads
328 * attempt updates including potentially calling the remapping function
329 * multiple times.
330 *
331 * <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 * @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 while ((oldValue = get(key)) != null) {
347 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 return null;
353 }
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 * <pre> {@code
366 * V oldValue = map.get(key);
367 * V newValue = remappingFunction.apply(key, oldValue);
368 * if (oldValue != null ) {
369 * if (newValue != null)
370 * map.replace(key, oldValue, newValue);
371 * else
372 * map.remove(key, oldValue);
373 * } else {
374 * if (newValue != null)
375 * map.putIfAbsent(key, newValue);
376 * else
377 * return null;
378 * }
379 * }</pre>
380 *
381 * The default implementation may retry these steps when multiple
382 * 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 *
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 for (;;) {
401 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 }
438 }
439 }
440
441
442 /**
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 * <pre> {@code
451 * V oldValue = map.get(key);
452 * V newValue = (oldValue == null) ? value :
453 * remappingFunction.apply(oldValue, value);
454 * if (newValue == null)
455 * map.remove(key);
456 * else
457 * map.put(key, newValue);
458 * }</pre>
459 *
460 * <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 *
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 }