jdk/src/java.base/share/classes/java/util/concurrent/ConcurrentMap.java
changeset 30441 415a5242e046
parent 25859 3317bb8137f4
child 32991 b27c76b82713
equal deleted inserted replaced
30440:376bb53438b7 30441:415a5242e046
    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
   456                 }
   464                 }
   457             }
   465             }
   458         }
   466         }
   459     }
   467     }
   460 
   468 
   461 
       
   462     /**
   469     /**
   463      * {@inheritDoc}
   470      * {@inheritDoc}
   464      *
   471      *
   465      * @implSpec
   472      * @implSpec
   466      * The default implementation is equivalent to performing the following
   473      * The default implementation is equivalent to performing the following
   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      *