ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/jsr166/jsr166/src/main/java/util/concurrent/ConcurrentMap.java
Revision: 1.53
Committed: Wed Dec 31 07:54:13 2014 UTC (9 years, 5 months ago) by jsr166
Branch: MAIN
Changes since 1.52: +1 -0 lines
Log Message:
standardize import statement order

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