32 * Expert Group and released to the public domain, as explained at |
32 * Expert Group and released to the public domain, as explained at |
33 * http://creativecommons.org/publicdomain/zero/1.0/ |
33 * http://creativecommons.org/publicdomain/zero/1.0/ |
34 */ |
34 */ |
35 |
35 |
36 package java.util.concurrent; |
36 package java.util.concurrent; |
|
37 |
37 import java.util.Map; |
38 import java.util.Map; |
38 import java.util.Objects; |
39 import java.util.Objects; |
39 import java.util.function.BiConsumer; |
40 import java.util.function.BiConsumer; |
40 import java.util.function.BiFunction; |
41 import java.util.function.BiFunction; |
41 import java.util.function.Function; |
42 import java.util.function.Function; |
42 |
43 |
43 /** |
44 /** |
44 * A {@link java.util.Map} providing thread safety and atomicity |
45 * A {@link java.util.Map} providing thread safety and atomicity |
45 * guarantees. |
46 * guarantees. |
|
47 * |
|
48 * <p>To maintain the specified guarantees, default implementations of |
|
49 * methods including {@link #putIfAbsent} inherited from {@link Map} |
|
50 * must be overridden by implementations of this interface. Similarly, |
|
51 * implementations of the collections returned by methods {@link |
|
52 * #keySet}, {@link #values}, and {@link #entrySet} must override |
|
53 * methods such as {@code removeIf} when necessary to |
|
54 * preserve atomicity guarantees. |
46 * |
55 * |
47 * <p>Memory consistency effects: As with other concurrent |
56 * <p>Memory consistency effects: As with other concurrent |
48 * collections, actions in a thread prior to placing an object into a |
57 * collections, actions in a thread prior to placing an object into a |
49 * {@code ConcurrentMap} as a key or value |
58 * {@code ConcurrentMap} as a key or value |
50 * <a href="package-summary.html#MemoryVisibility"><i>happen-before</i></a> |
59 * <a href="package-summary.html#MemoryVisibility"><i>happen-before</i></a> |
58 * @since 1.5 |
67 * @since 1.5 |
59 * @author Doug Lea |
68 * @author Doug Lea |
60 * @param <K> the type of keys maintained by this map |
69 * @param <K> the type of keys maintained by this map |
61 * @param <V> the type of mapped values |
70 * @param <V> the type of mapped values |
62 */ |
71 */ |
63 public interface ConcurrentMap<K, V> extends Map<K, V> { |
72 public interface ConcurrentMap<K,V> extends Map<K,V> { |
64 |
73 |
65 /** |
74 /** |
66 * {@inheritDoc} |
75 * {@inheritDoc} |
67 * |
76 * |
68 * @implNote This implementation assumes that the ConcurrentMap cannot |
77 * @implNote This implementation assumes that the ConcurrentMap cannot |
84 * {@inheritDoc} |
93 * {@inheritDoc} |
85 * |
94 * |
86 * @implSpec The default implementation is equivalent to, for this |
95 * @implSpec The default implementation is equivalent to, for this |
87 * {@code map}: |
96 * {@code map}: |
88 * <pre> {@code |
97 * <pre> {@code |
89 * for ((Map.Entry<K, V> entry : map.entrySet()) |
98 * for (Map.Entry<K,V> entry : map.entrySet()) { |
90 * action.accept(entry.getKey(), entry.getValue()); |
99 * action.accept(entry.getKey(), entry.getValue()); |
91 * }</pre> |
100 * }}</pre> |
92 * |
101 * |
93 * @implNote The default implementation assumes that |
102 * @implNote The default implementation assumes that |
94 * {@code IllegalStateException} thrown by {@code getKey()} or |
103 * {@code IllegalStateException} thrown by {@code getKey()} or |
95 * {@code getValue()} indicates that the entry has been removed and cannot |
104 * {@code getValue()} indicates that the entry has been removed and cannot |
96 * be processed. Operation continues for subsequent entries. |
105 * be processed. Operation continues for subsequent entries. |
99 * @since 1.8 |
108 * @since 1.8 |
100 */ |
109 */ |
101 @Override |
110 @Override |
102 default void forEach(BiConsumer<? super K, ? super V> action) { |
111 default void forEach(BiConsumer<? super K, ? super V> action) { |
103 Objects.requireNonNull(action); |
112 Objects.requireNonNull(action); |
104 for (Map.Entry<K, V> entry : entrySet()) { |
113 for (Map.Entry<K,V> entry : entrySet()) { |
105 K k; |
114 K k; |
106 V v; |
115 V v; |
107 try { |
116 try { |
108 k = entry.getKey(); |
117 k = entry.getKey(); |
109 v = entry.getValue(); |
118 v = entry.getValue(); |
110 } catch(IllegalStateException ise) { |
119 } catch (IllegalStateException ise) { |
111 // this usually means the entry is no longer in the map. |
120 // this usually means the entry is no longer in the map. |
112 continue; |
121 continue; |
113 } |
122 } |
114 action.accept(k, v); |
123 action.accept(k, v); |
115 } |
124 } |
116 } |
125 } |
117 |
126 |
118 /** |
127 /** |
119 * If the specified key is not already associated |
128 * If the specified key is not already associated |
120 * with a value, associate it with the given value. |
129 * with a value, associates it with the given value. |
121 * This is equivalent to |
130 * This is equivalent to, for this {@code map}: |
122 * <pre> {@code |
131 * <pre> {@code |
123 * if (!map.containsKey(key)) |
132 * if (!map.containsKey(key)) |
124 * return map.put(key, value); |
133 * return map.put(key, value); |
125 * else |
134 * else |
126 * return map.get(key); |
135 * return map.get(key);}</pre> |
127 * }</pre> |
|
128 * |
136 * |
129 * except that the action is performed atomically. |
137 * except that the action is performed atomically. |
130 * |
138 * |
131 * @implNote This implementation intentionally re-abstracts the |
139 * @implNote This implementation intentionally re-abstracts the |
132 * inappropriate default provided in {@code Map}. |
140 * inappropriate default provided in {@code Map}. |
145 * @throws NullPointerException if the specified key or value is null, |
153 * @throws NullPointerException if the specified key or value is null, |
146 * and this map does not permit null keys or values |
154 * and this map does not permit null keys or values |
147 * @throws IllegalArgumentException if some property of the specified key |
155 * @throws IllegalArgumentException if some property of the specified key |
148 * or value prevents it from being stored in this map |
156 * or value prevents it from being stored in this map |
149 */ |
157 */ |
150 V putIfAbsent(K key, V value); |
158 V putIfAbsent(K key, V value); |
151 |
159 |
152 /** |
160 /** |
153 * Removes the entry for a key only if currently mapped to a given value. |
161 * Removes the entry for a key only if currently mapped to a given value. |
154 * This is equivalent to |
162 * This is equivalent to, for this {@code map}: |
155 * <pre> {@code |
163 * <pre> {@code |
156 * if (map.containsKey(key) && Objects.equals(map.get(key), value)) { |
164 * if (map.containsKey(key) |
|
165 * && Objects.equals(map.get(key), value)) { |
157 * map.remove(key); |
166 * map.remove(key); |
158 * return true; |
167 * return true; |
159 * } else |
168 * } else { |
160 * return false; |
169 * return false; |
161 * }</pre> |
170 * }}</pre> |
162 * |
171 * |
163 * except that the action is performed atomically. |
172 * except that the action is performed atomically. |
164 * |
173 * |
165 * @implNote This implementation intentionally re-abstracts the |
174 * @implNote This implementation intentionally re-abstracts the |
166 * inappropriate default provided in {@code Map}. |
175 * inappropriate default provided in {@code Map}. |
179 */ |
188 */ |
180 boolean remove(Object key, Object value); |
189 boolean remove(Object key, Object value); |
181 |
190 |
182 /** |
191 /** |
183 * Replaces the entry for a key only if currently mapped to a given value. |
192 * Replaces the entry for a key only if currently mapped to a given value. |
184 * This is equivalent to |
193 * This is equivalent to, for this {@code map}: |
185 * <pre> {@code |
194 * <pre> {@code |
186 * if (map.containsKey(key) && Objects.equals(map.get(key), oldValue)) { |
195 * if (map.containsKey(key) |
|
196 * && Objects.equals(map.get(key), oldValue)) { |
187 * map.put(key, newValue); |
197 * map.put(key, newValue); |
188 * return true; |
198 * return true; |
189 * } else |
199 * } else { |
190 * return false; |
200 * return false; |
191 * }</pre> |
201 * }}</pre> |
192 * |
202 * |
193 * except that the action is performed atomically. |
203 * except that the action is performed atomically. |
194 * |
204 * |
195 * @implNote This implementation intentionally re-abstracts the |
205 * @implNote This implementation intentionally re-abstracts the |
196 * inappropriate default provided in {@code Map}. |
206 * inappropriate default provided in {@code Map}. |
210 */ |
220 */ |
211 boolean replace(K key, V oldValue, V newValue); |
221 boolean replace(K key, V oldValue, V newValue); |
212 |
222 |
213 /** |
223 /** |
214 * Replaces the entry for a key only if currently mapped to some value. |
224 * Replaces the entry for a key only if currently mapped to some value. |
215 * This is equivalent to |
225 * This is equivalent to, for this {@code map}: |
216 * <pre> {@code |
226 * <pre> {@code |
217 * if (map.containsKey(key)) { |
227 * if (map.containsKey(key)) |
218 * return map.put(key, value); |
228 * return map.put(key, value); |
219 * } else |
229 * else |
220 * return null; |
230 * return null;}</pre> |
221 * }</pre> |
|
222 * |
231 * |
223 * except that the action is performed atomically. |
232 * except that the action is performed atomically. |
224 * |
233 * |
225 * @implNote This implementation intentionally re-abstracts the |
234 * @implNote This implementation intentionally re-abstracts the |
226 * inappropriate default provided in {@code Map}. |
235 * inappropriate default provided in {@code Map}. |
247 * {@inheritDoc} |
256 * {@inheritDoc} |
248 * |
257 * |
249 * @implSpec |
258 * @implSpec |
250 * <p>The default implementation is equivalent to, for this {@code map}: |
259 * <p>The default implementation is equivalent to, for this {@code map}: |
251 * <pre> {@code |
260 * <pre> {@code |
252 * for ((Map.Entry<K, V> entry : map.entrySet()) |
261 * for (Map.Entry<K,V> entry : map.entrySet()) { |
253 * do { |
262 * K k; |
254 * K k = entry.getKey(); |
263 * V v; |
255 * V v = entry.getValue(); |
264 * do { |
256 * } while(!replace(k, v, function.apply(k, v))); |
265 * k = entry.getKey(); |
257 * }</pre> |
266 * v = entry.getValue(); |
|
267 * } while (!map.replace(k, v, function.apply(k, v))); |
|
268 * }}</pre> |
258 * |
269 * |
259 * The default implementation may retry these steps when multiple |
270 * The default implementation may retry these steps when multiple |
260 * threads attempt updates including potentially calling the function |
271 * threads attempt updates including potentially calling the function |
261 * repeatedly for a given key. |
272 * repeatedly for a given key. |
262 * |
273 * |
273 */ |
284 */ |
274 @Override |
285 @Override |
275 default void replaceAll(BiFunction<? super K, ? super V, ? extends V> function) { |
286 default void replaceAll(BiFunction<? super K, ? super V, ? extends V> function) { |
276 Objects.requireNonNull(function); |
287 Objects.requireNonNull(function); |
277 forEach((k,v) -> { |
288 forEach((k,v) -> { |
278 while(!replace(k, v, function.apply(k, v))) { |
289 while (!replace(k, v, function.apply(k, v))) { |
279 // v changed or k is gone |
290 // v changed or k is gone |
280 if ( (v = get(k)) == null) { |
291 if ( (v = get(k)) == null) { |
281 // k is no longer in the map. |
292 // k is no longer in the map. |
282 break; |
293 break; |
283 } |
294 } |
293 * {@code map}, then returning the current value or {@code null} if now |
304 * {@code map}, then returning the current value or {@code null} if now |
294 * absent: |
305 * absent: |
295 * |
306 * |
296 * <pre> {@code |
307 * <pre> {@code |
297 * if (map.get(key) == null) { |
308 * if (map.get(key) == null) { |
298 * V newValue = mappingFunction.apply(key); |
309 * V newValue = mappingFunction.apply(key); |
299 * if (newValue != null) |
310 * if (newValue != null) |
300 * return map.putIfAbsent(key, newValue); |
311 * return map.putIfAbsent(key, newValue); |
301 * } |
312 * }}</pre> |
302 * }</pre> |
|
303 * |
313 * |
304 * The default implementation may retry these steps when multiple |
314 * The default implementation may retry these steps when multiple |
305 * threads attempt updates including potentially calling the mapping |
315 * threads attempt updates including potentially calling the mapping |
306 * function multiple times. |
316 * function multiple times. |
307 * |
317 * |
329 * {@inheritDoc} |
339 * {@inheritDoc} |
330 * |
340 * |
331 * @implSpec |
341 * @implSpec |
332 * The default implementation is equivalent to performing the following |
342 * The default implementation is equivalent to performing the following |
333 * steps for this {@code map}, then returning the current value or |
343 * steps for this {@code map}, then returning the current value or |
334 * {@code null} if now absent. : |
344 * {@code null} if now absent: |
335 * |
345 * |
336 * <pre> {@code |
346 * <pre> {@code |
337 * if (map.get(key) != null) { |
347 * if (map.get(key) != null) { |
338 * V oldValue = map.get(key); |
348 * V oldValue = map.get(key); |
339 * V newValue = remappingFunction.apply(key, oldValue); |
349 * V newValue = remappingFunction.apply(key, oldValue); |
340 * if (newValue != null) |
350 * if (newValue != null) |
341 * map.replace(key, oldValue, newValue); |
351 * map.replace(key, oldValue, newValue); |
342 * else |
352 * else |
343 * map.remove(key, oldValue); |
353 * map.remove(key, oldValue); |
344 * } |
354 * }}</pre> |
345 * }</pre> |
|
346 * |
355 * |
347 * The default implementation may retry these steps when multiple threads |
356 * The default implementation may retry these steps when multiple threads |
348 * attempt updates including potentially calling the remapping function |
357 * attempt updates including potentially calling the remapping function |
349 * multiple times. |
358 * multiple times. |
350 * |
359 * |
361 @Override |
370 @Override |
362 default V computeIfPresent(K key, |
371 default V computeIfPresent(K key, |
363 BiFunction<? super K, ? super V, ? extends V> remappingFunction) { |
372 BiFunction<? super K, ? super V, ? extends V> remappingFunction) { |
364 Objects.requireNonNull(remappingFunction); |
373 Objects.requireNonNull(remappingFunction); |
365 V oldValue; |
374 V oldValue; |
366 while((oldValue = get(key)) != null) { |
375 while ((oldValue = get(key)) != null) { |
367 V newValue = remappingFunction.apply(key, oldValue); |
376 V newValue = remappingFunction.apply(key, oldValue); |
368 if (newValue != null) { |
377 if (newValue != null) { |
369 if (replace(key, oldValue, newValue)) |
378 if (replace(key, oldValue, newValue)) |
370 return newValue; |
379 return newValue; |
371 } else if (remove(key, oldValue)) |
380 } else if (remove(key, oldValue)) |
372 return null; |
381 return null; |
373 } |
382 } |
374 return oldValue; |
383 return oldValue; |
375 } |
384 } |
376 |
385 |
377 /** |
386 /** |
384 * |
393 * |
385 * <pre> {@code |
394 * <pre> {@code |
386 * V oldValue = map.get(key); |
395 * V oldValue = map.get(key); |
387 * V newValue = remappingFunction.apply(key, oldValue); |
396 * V newValue = remappingFunction.apply(key, oldValue); |
388 * if (oldValue != null ) { |
397 * if (oldValue != null ) { |
389 * if (newValue != null) |
398 * if (newValue != null) |
390 * map.replace(key, oldValue, newValue); |
399 * map.replace(key, oldValue, newValue); |
391 * else |
400 * else |
392 * map.remove(key, oldValue); |
401 * map.remove(key, oldValue); |
393 * } else { |
402 * } else { |
394 * if (newValue != null) |
403 * if (newValue != null) |
395 * map.putIfAbsent(key, newValue); |
404 * map.putIfAbsent(key, newValue); |
396 * else |
405 * else |
397 * return null; |
406 * return null; |
398 * } |
407 * }}</pre> |
399 * }</pre> |
|
400 * |
408 * |
401 * The default implementation may retry these steps when multiple |
409 * The default implementation may retry these steps when multiple |
402 * threads attempt updates including potentially calling the remapping |
410 * threads attempt updates including potentially calling the remapping |
403 * function multiple times. |
411 * function multiple times. |
404 * |
412 * |
415 @Override |
423 @Override |
416 default V compute(K key, |
424 default V compute(K key, |
417 BiFunction<? super K, ? super V, ? extends V> remappingFunction) { |
425 BiFunction<? super K, ? super V, ? extends V> remappingFunction) { |
418 Objects.requireNonNull(remappingFunction); |
426 Objects.requireNonNull(remappingFunction); |
419 V oldValue = get(key); |
427 V oldValue = get(key); |
420 for(;;) { |
428 for (;;) { |
421 V newValue = remappingFunction.apply(key, oldValue); |
429 V newValue = remappingFunction.apply(key, oldValue); |
422 if (newValue == null) { |
430 if (newValue == null) { |
423 // delete mapping |
431 // delete mapping |
424 if (oldValue != null || containsKey(key)) { |
432 if (oldValue != null || containsKey(key)) { |
425 // something to remove |
433 // something to remove |
468 * {@code null} if absent: |
475 * {@code null} if absent: |
469 * |
476 * |
470 * <pre> {@code |
477 * <pre> {@code |
471 * V oldValue = map.get(key); |
478 * V oldValue = map.get(key); |
472 * V newValue = (oldValue == null) ? value : |
479 * V newValue = (oldValue == null) ? value : |
473 * remappingFunction.apply(oldValue, value); |
480 * remappingFunction.apply(oldValue, value); |
474 * if (newValue == null) |
481 * if (newValue == null) |
475 * map.remove(key); |
482 * map.remove(key); |
476 * else |
483 * else |
477 * map.put(key, newValue); |
484 * map.put(key, newValue);}</pre> |
478 * }</pre> |
|
479 * |
485 * |
480 * <p>The default implementation may retry these steps when multiple |
486 * <p>The default implementation may retry these steps when multiple |
481 * threads attempt updates including potentially calling the remapping |
487 * threads attempt updates including potentially calling the remapping |
482 * function multiple times. |
488 * function multiple times. |
483 * |
489 * |