ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/jsr166/jsr166/src/jdk8/java/util/concurrent/ConcurrentMap.java
Revision: 1.1
Committed: Sat Mar 26 06:22:49 2016 UTC (8 years, 2 months ago) by jsr166
Branch: MAIN
CVS Tags: HEAD
Log Message:
fork jdk8 maintenance branch for source and jtreg tests

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)
136 * && 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="{@docRoot}/../api/java/util/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="{@docRoot}/../api/java/util/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, for this {@code map}:
165 * <pre> {@code
166 * if (map.containsKey(key)
167 * && Objects.equals(map.get(key), oldValue)) {
168 * map.put(key, newValue);
169 * return true;
170 * } else {
171 * return false;
172 * }}</pre>
173 *
174 * except that the action is performed atomically.
175 *
176 * @implNote This implementation intentionally re-abstracts the
177 * inappropriate default provided in {@code Map}.
178 *
179 * @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 * @return {@code true} if the value was replaced
183 * @throws UnsupportedOperationException if the {@code put} operation
184 * is not supported by this map
185 * @throws ClassCastException if the class of a specified key or value
186 * prevents it from being stored in this map
187 * @throws NullPointerException if a specified key or value is null,
188 * and this map does not permit null keys or values
189 * @throws IllegalArgumentException if some property of a specified key
190 * or value prevents it from being stored in this map
191 */
192 boolean replace(K key, V oldValue, V newValue);
193
194 /**
195 * Replaces the entry for a key only if currently mapped to some value.
196 * This is equivalent to, for this {@code map}:
197 * <pre> {@code
198 * if (map.containsKey(key))
199 * return map.put(key, value);
200 * else
201 * return null;}</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 * 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 including potentially calling the function
243 * repeatedly for a given key.
244 *
245 * <p>This implementation assumes that the ConcurrentMap cannot contain null
246 * values and {@code get()} returning null unambiguously means the key is
247 * absent. Implementations which support null values <strong>must</strong>
248 * override this default implementation.
249 *
250 * @throws UnsupportedOperationException {@inheritDoc}
251 * @throws NullPointerException {@inheritDoc}
252 * @throws ClassCastException {@inheritDoc}
253 * @throws IllegalArgumentException {@inheritDoc}
254 * @since 1.8
255 */
256 @Override
257 default void replaceAll(BiFunction<? super K, ? super V, ? extends V> function) {
258 Objects.requireNonNull(function);
259 forEach((k,v) -> {
260 while (!replace(k, v, function.apply(k, v))) {
261 // v changed or k is gone
262 if ( (v = get(k)) == null) {
263 // k is no longer in the map.
264 break;
265 }
266 }
267 });
268 }
269
270 /**
271 * {@inheritDoc}
272 *
273 * @implSpec
274 * The default implementation is equivalent to the following steps for this
275 * {@code map}:
276 *
277 * <pre> {@code
278 * V oldValue, newValue;
279 * return ((oldValue = map.get(key)) == null
280 * && (newValue = mappingFunction.apply(key)) != null
281 * && (oldValue = map.putIfAbsent(key, newValue)) == null)
282 * ? newValue
283 * : oldValue;}</pre>
284 *
285 * <p>This implementation assumes that the ConcurrentMap cannot contain null
286 * values and {@code get()} returning null unambiguously means the key is
287 * absent. Implementations which support null values <strong>must</strong>
288 * override this default implementation.
289 *
290 * @throws UnsupportedOperationException {@inheritDoc}
291 * @throws ClassCastException {@inheritDoc}
292 * @throws NullPointerException {@inheritDoc}
293 * @throws IllegalArgumentException {@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 oldValue, newValue;
301 return ((oldValue = get(key)) == null
302 && (newValue = mappingFunction.apply(key)) != null
303 && (oldValue = putIfAbsent(key, newValue)) == null)
304 ? newValue
305 : oldValue;
306 }
307
308 /**
309 * {@inheritDoc}
310 *
311 * @implSpec
312 * The default implementation is equivalent to performing the following
313 * steps for this {@code map}:
314 *
315 * <pre> {@code
316 * for (V oldValue; (oldValue = map.get(key)) != null; ) {
317 * V newValue = remappingFunction.apply(key, oldValue);
318 * if ((newValue == null)
319 * ? map.remove(key, oldValue)
320 * : map.replace(key, oldValue, newValue))
321 * return newValue;
322 * }
323 * return null;}</pre>
324 * When multiple threads attempt updates, map operations and the
325 * remapping function may be called multiple times.
326 *
327 * <p>This implementation assumes that the ConcurrentMap cannot contain null
328 * values and {@code get()} returning null unambiguously means the key is
329 * absent. Implementations which support null values <strong>must</strong>
330 * override this default implementation.
331 *
332 * @throws UnsupportedOperationException {@inheritDoc}
333 * @throws ClassCastException {@inheritDoc}
334 * @throws NullPointerException {@inheritDoc}
335 * @throws IllegalArgumentException {@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 for (V oldValue; (oldValue = get(key)) != null; ) {
343 V newValue = remappingFunction.apply(key, oldValue);
344 if ((newValue == null)
345 ? remove(key, oldValue)
346 : replace(key, oldValue, newValue))
347 return newValue;
348 }
349 return null;
350 }
351
352 /**
353 * {@inheritDoc}
354 *
355 * @implSpec
356 * The default implementation is equivalent to performing the following
357 * steps for this {@code map}:
358 *
359 * <pre> {@code
360 * for (;;) {
361 * V oldValue = map.get(key);
362 * V newValue = remappingFunction.apply(key, oldValue);
363 * if (newValue != null) {
364 * if ((oldValue != null)
365 * ? map.replace(key, oldValue, newValue)
366 * : map.putIfAbsent(key, newValue) == null)
367 * return newValue;
368 * } else if (oldValue == null || map.remove(key, oldValue)) {
369 * return null;
370 * }
371 * }}</pre>
372 * When multiple threads attempt updates, map operations and the
373 * remapping function may be called multiple times.
374 *
375 * <p>This implementation assumes that the ConcurrentMap cannot contain null
376 * values and {@code get()} returning null unambiguously means the key is
377 * absent. Implementations which support null values <strong>must</strong>
378 * override this default implementation.
379 *
380 * @throws UnsupportedOperationException {@inheritDoc}
381 * @throws ClassCastException {@inheritDoc}
382 * @throws NullPointerException {@inheritDoc}
383 * @throws IllegalArgumentException {@inheritDoc}
384 * @since 1.8
385 */
386 @Override
387 default V compute(K key,
388 BiFunction<? super K, ? super V, ? extends V> remappingFunction) {
389 retry: for (;;) {
390 V oldValue = get(key);
391 // if putIfAbsent fails, opportunistically use its return value
392 haveOldValue: for (;;) {
393 V newValue = remappingFunction.apply(key, oldValue);
394 if (newValue != null) {
395 if (oldValue != null) {
396 if (replace(key, oldValue, newValue))
397 return newValue;
398 }
399 else if ((oldValue = putIfAbsent(key, newValue)) == null)
400 return newValue;
401 else continue haveOldValue;
402 } else if (oldValue == null || remove(key, oldValue)) {
403 return null;
404 }
405 continue retry;
406 }
407 }
408 }
409
410 /**
411 * {@inheritDoc}
412 *
413 * @implSpec
414 * The default implementation is equivalent to performing the following
415 * steps for this {@code map}:
416 *
417 * <pre> {@code
418 * for (;;) {
419 * V oldValue = map.get(key);
420 * if (oldValue != null) {
421 * V newValue = remappingFunction.apply(oldValue, value);
422 * if (newValue != null) {
423 * if (map.replace(key, oldValue, newValue))
424 * return newValue;
425 * } else if (map.remove(key, oldValue)) {
426 * return null;
427 * }
428 * } else if (map.putIfAbsent(key, value) == null) {
429 * return value;
430 * }
431 * }}</pre>
432 * When multiple threads attempt updates, map operations and the
433 * remapping function may be called multiple times.
434 *
435 * <p>This implementation assumes that the ConcurrentMap cannot contain null
436 * values and {@code get()} returning null unambiguously means the key is
437 * absent. Implementations which support null values <strong>must</strong>
438 * override this default implementation.
439 *
440 * @throws UnsupportedOperationException {@inheritDoc}
441 * @throws ClassCastException {@inheritDoc}
442 * @throws NullPointerException {@inheritDoc}
443 * @throws IllegalArgumentException {@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 retry: for (;;) {
452 V oldValue = get(key);
453 // if putIfAbsent fails, opportunistically use its return value
454 haveOldValue: for (;;) {
455 if (oldValue != null) {
456 V newValue = remappingFunction.apply(oldValue, value);
457 if (newValue != null) {
458 if (replace(key, oldValue, newValue))
459 return newValue;
460 } else if (remove(key, oldValue)) {
461 return null;
462 }
463 continue retry;
464 } else {
465 if ((oldValue = putIfAbsent(key, value)) == null)
466 return value;
467 continue haveOldValue;
468 }
469 }
470 }
471 }
472 }