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, 1 month ago) by jsr166
Branch: MAIN
CVS Tags: HEAD
Log Message:
fork jdk8 maintenance branch for source and jtreg tests

File Contents

# User Rev Content
1 jsr166 1.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     }