ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/jsr166/jsr166/src/main/java/util/concurrent/ConcurrentMap.java
Revision: 1.60
Committed: Thu Apr 30 18:47:12 2015 UTC (9 years, 1 month ago) by jsr166
Branch: MAIN
Changes since 1.59: +5 -5 lines
Log Message:
add "for this map"

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, associates it with the given value.
101 * This is equivalent to, for this {@code map}:
102 * <pre> {@code
103 * if (!map.containsKey(key))
104 * return map.put(key, value);
105 * else
106 * return map.get(key);}</pre>
107 *
108 * except that the action is performed atomically.
109 *
110 * @implNote This implementation intentionally re-abstracts the
111 * inappropriate default provided in {@code Map}.
112 *
113 * @param key key with which the specified value is to be associated
114 * @param value value to be associated with the specified key
115 * @return the previous value associated with the specified key, or
116 * {@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 * if the implementation supports null values.)
120 * @throws UnsupportedOperationException if the {@code put} operation
121 * is not supported by this map
122 * @throws ClassCastException if the class of the specified key or value
123 * 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 */
129 V putIfAbsent(K key, V value);
130
131 /**
132 * Removes the entry for a key only if currently mapped to a given value.
133 * This is equivalent to, for this {@code map}:
134 * <pre> {@code
135 * if (map.containsKey(key) && Objects.equals(map.get(key), value)) {
136 * map.remove(key);
137 * return true;
138 * } else {
139 * return false;
140 * }}</pre>
141 *
142 * except that the action is performed atomically.
143 *
144 * @implNote This implementation intentionally re-abstracts the
145 * inappropriate default provided in {@code Map}.
146 *
147 * @param key key with which the specified value is associated
148 * @param value value expected to be associated with the specified key
149 * @return {@code true} if the value was removed
150 * @throws UnsupportedOperationException if the {@code remove} operation
151 * is not supported by this map
152 * @throws ClassCastException if the key or value is of an inappropriate
153 * type for this map
154 * (<a href="../Collection.html#optional-restrictions">optional</a>)
155 * @throws NullPointerException if the specified key or value is null,
156 * and this map does not permit null keys or values
157 * (<a href="../Collection.html#optional-restrictions">optional</a>)
158 */
159 boolean remove(Object key, Object value);
160
161 /**
162 * Replaces the entry for a key only if currently mapped to a given value.
163 * This is equivalent to, for this {@code map}:
164 * <pre> {@code
165 * if (map.containsKey(key) && Objects.equals(map.get(key), oldValue)) {
166 * map.put(key, newValue);
167 * return true;
168 * } else {
169 * return false;
170 * }}</pre>
171 *
172 * except that the action is performed atomically.
173 *
174 * @implNote This implementation intentionally re-abstracts the
175 * inappropriate default provided in {@code Map}.
176 *
177 * @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 * @return {@code true} if the value was replaced
181 * @throws UnsupportedOperationException if the {@code put} operation
182 * is not supported by this map
183 * @throws ClassCastException if the class of a specified key or value
184 * prevents it from being stored in this map
185 * @throws NullPointerException if a specified key or value is null,
186 * and this map does not permit null keys or values
187 * @throws IllegalArgumentException if some property of a specified key
188 * or value prevents it from being stored in this map
189 */
190 boolean replace(K key, V oldValue, V newValue);
191
192 /**
193 * Replaces the entry for a key only if currently mapped to some value.
194 * This is equivalent to, for this {@code map}:
195 * <pre> {@code
196 * if (map.containsKey(key)) {
197 * return map.put(key, value);
198 * } else {
199 * return null;
200 * }}</pre>
201 *
202 * except that the action is performed atomically.
203 *
204 * @implNote This implementation intentionally re-abstracts the
205 * inappropriate default provided in {@code Map}.
206 *
207 * @param key key with which the specified value is associated
208 * @param value value to be associated with the specified key
209 * @return the previous value associated with the specified key, or
210 * {@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 * if the implementation supports null values.)
214 * @throws UnsupportedOperationException if the {@code put} operation
215 * is not supported by this map
216 * @throws ClassCastException if the class of the specified key or value
217 * prevents it from being stored in this map
218 * @throws NullPointerException if the specified key or value is null,
219 * and this map does not permit null keys or values
220 * @throws IllegalArgumentException if some property of the specified key
221 * or value prevents it from being stored in this map
222 */
223 V replace(K key, V value);
224
225 /**
226 * {@inheritDoc}
227 *
228 * @implSpec
229 * <p>The default implementation is equivalent to, for this {@code map}:
230 * <pre> {@code
231 * for (Map.Entry<K,V> entry : map.entrySet()) {
232 * do {
233 * K k = entry.getKey();
234 * V v = entry.getValue();
235 * } while (!replace(k, v, function.apply(k, v)));
236 * }}</pre>
237 *
238 * The default implementation may retry these steps when multiple
239 * 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 *
247 * @throws UnsupportedOperationException {@inheritDoc}
248 * @throws NullPointerException {@inheritDoc}
249 * @throws ClassCastException {@inheritDoc}
250 * @throws IllegalArgumentException {@inheritDoc}
251 * @since 1.8
252 */
253 @Override
254 default void replaceAll(BiFunction<? super K, ? super V, ? extends V> function) {
255 Objects.requireNonNull(function);
256 forEach((k,v) -> {
257 while (!replace(k, v, function.apply(k, v))) {
258 // v changed or k is gone
259 if ( (v = get(k)) == null) {
260 // k is no longer in the map.
261 break;
262 }
263 }
264 });
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 * <pre> {@code
276 * if (map.get(key) == null) {
277 * V newValue = mappingFunction.apply(key);
278 * if (newValue != null)
279 * return map.putIfAbsent(key, newValue);
280 * }}</pre>
281 *
282 * The default implementation may retry these steps when multiple
283 * 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 *
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
306 /**
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 * {@code null} if now absent:
313 *
314 * <pre> {@code
315 * if (map.get(key) != null) {
316 * 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 *
324 * The default implementation may retry these steps when multiple threads
325 * attempt updates including potentially calling the remapping function
326 * multiple times.
327 *
328 * <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 * @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 while ((oldValue = get(key)) != null) {
344 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 return null;
350 }
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 * <pre> {@code
363 * V oldValue = map.get(key);
364 * V newValue = remappingFunction.apply(key, oldValue);
365 * if (oldValue != null ) {
366 * if (newValue != null)
367 * map.replace(key, oldValue, newValue);
368 * else
369 * map.remove(key, oldValue);
370 * } else {
371 * if (newValue != null)
372 * map.putIfAbsent(key, newValue);
373 * else
374 * return null;
375 * }}</pre>
376 *
377 * The default implementation may retry these steps when multiple
378 * 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 *
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 for (;;) {
397 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 }
434 }
435 }
436
437 /**
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 * <pre> {@code
446 * V oldValue = map.get(key);
447 * V newValue = (oldValue == null) ? value :
448 * remappingFunction.apply(oldValue, value);
449 * if (newValue == null)
450 * map.remove(key);
451 * else
452 * map.put(key, newValue);}</pre>
453 *
454 * <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 *
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 }