1 /*
   2  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   3  *
   4  * This code is free software; you can redistribute it and/or modify it
   5  * under the terms of the GNU General Public License version 2 only, as
   6  * published by the Free Software Foundation.  Oracle designates this
   7  * particular file as subject to the "Classpath" exception as provided
   8  * by Oracle in the LICENSE file that accompanied this code.
   9  *
  10  * This code is distributed in the hope that it will be useful, but WITHOUT
  11  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  12  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  13  * version 2 for more details (a copy is included in the LICENSE file that
  14  * accompanied this code).
  15  *
  16  * You should have received a copy of the GNU General Public License version
  17  * 2 along with this work; if not, write to the Free Software Foundation,
  18  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  19  *
  20  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  21  * or visit www.oracle.com if you need additional information or have any
  22  * questions.
  23  */
  24 
  25 /*
  26  * This file is available under and governed by the GNU General Public
  27  * License version 2 only, as published by the Free Software Foundation.
  28  * However, the following notice accompanied the original version of this
  29  * file:
  30  *
  31  * Written by Doug Lea with assistance from members of JCP JSR-166
  32  * Expert Group and released to the public domain, as explained at
  33  * http://creativecommons.org/publicdomain/zero/1.0/
  34  */
  35 
  36 package java.util.concurrent;
  37 import java.util.Map;
  38 import java.util.Objects;
  39 import java.util.function.BiConsumer;
  40 import java.util.function.BiFunction;
  41 import java.util.function.Function;
  42 
  43 /**
  44  * A {@link java.util.Map} providing thread safety and atomicity
  45  * guarantees.
  46  *
  47  * <p>Memory consistency effects: As with other concurrent
  48  * collections, actions in a thread prior to placing an object into a
  49  * {@code ConcurrentMap} as a key or value
  50  * <a href="package-summary.html#MemoryVisibility"><i>happen-before</i></a>
  51  * actions subsequent to the access or removal of that object from
  52  * the {@code ConcurrentMap} in another thread.
  53  *
  54  * <p>This interface is a member of the
  55  * <a href="{@docRoot}/../technotes/guides/collections/index.html">
  56  * Java Collections Framework</a>.
  57  *
  58  * @since 1.5
  59  * @author Doug Lea
  60  * @param <K> the type of keys maintained by this map
  61  * @param <V> the type of mapped values
  62  */
  63 public interface ConcurrentMap<K, V> extends Map<K, V> {
  64 
  65     /**
  66      * {@inheritDoc}
  67      *
  68      * @implNote This implementation assumes that the ConcurrentMap cannot
  69      * contain null values and {@code get()} returning null unambiguously means
  70      * the key is absent. Implementations which support null values
  71      * <strong>must</strong> override this default implementation.
  72      *
  73      * @throws ClassCastException {@inheritDoc}
  74      * @throws NullPointerException {@inheritDoc}
  75      * @since 1.8
  76      */
  77     @Override
  78     default V getOrDefault(Object key, V defaultValue) {
  79         V v;
  80         return ((v = get(key)) != null) ? v : defaultValue;
  81     }
  82 
  83    /**
  84      * {@inheritDoc}
  85      *
  86      * @implSpec The default implementation is equivalent to, for this
  87      * {@code map}:
  88      * <pre> {@code
  89      * for ((Map.Entry<K, V> entry : map.entrySet())
  90      *     action.accept(entry.getKey(), entry.getValue());
  91      * }</pre>
  92      *
  93      * @implNote The default implementation assumes that
  94      * {@code IllegalStateException} thrown by {@code getKey()} or
  95      * {@code getValue()} indicates that the entry has been removed and cannot
  96      * be processed. Operation continues for subsequent entries.
  97      *
  98      * @throws NullPointerException {@inheritDoc}
  99      * @since 1.8
 100      */
 101     @Override
 102     default void forEach(BiConsumer<? super K, ? super V> action) {
 103         Objects.requireNonNull(action);
 104         for (Map.Entry<K, V> entry : entrySet()) {
 105             K k;
 106             V v;
 107             try {
 108                 k = entry.getKey();
 109                 v = entry.getValue();
 110             } catch(IllegalStateException ise) {
 111                 // this usually means the entry is no longer in the map.
 112                 continue;
 113             }
 114             action.accept(k, v);
 115         }
 116     }
 117 
 118     /**
 119      * If the specified key is not already associated
 120      * with a value, associate it with the given value.
 121      * This is equivalent to
 122      *  <pre> {@code
 123      * if (!map.containsKey(key))
 124      *   return map.put(key, value);
 125      * else
 126      *   return map.get(key);
 127      * }</pre>
 128      *
 129      * except that the action is performed atomically.
 130      *
 131      * @implNote This implementation intentionally re-abstracts the
 132      * inappropriate default provided in {@code Map}.
 133      *
 134      * @param key key with which the specified value is to be associated
 135      * @param value value to be associated with the specified key
 136      * @return the previous value associated with the specified key, or
 137      *         {@code null} if there was no mapping for the key.
 138      *         (A {@code null} return can also indicate that the map
 139      *         previously associated {@code null} with the key,
 140      *         if the implementation supports null values.)
 141      * @throws UnsupportedOperationException if the {@code put} operation
 142      *         is not supported by this map
 143      * @throws ClassCastException if the class of the specified key or value
 144      *         prevents it from being stored in this map
 145      * @throws NullPointerException if the specified key or value is null,
 146      *         and this map does not permit null keys or values
 147      * @throws IllegalArgumentException if some property of the specified key
 148      *         or value prevents it from being stored in this map
 149      */
 150      V putIfAbsent(K key, V value);
 151 
 152     /**
 153      * Removes the entry for a key only if currently mapped to a given value.
 154      * This is equivalent to
 155      *  <pre> {@code
 156      * if (map.containsKey(key) && Objects.equals(map.get(key), value)) {
 157      *   map.remove(key);
 158      *   return true;
 159      * } else
 160      *   return false;
 161      * }</pre>
 162      *
 163      * except that the action is performed atomically.
 164      *
 165      * @implNote This implementation intentionally re-abstracts the
 166      * inappropriate default provided in {@code Map}.
 167      *
 168      * @param key key with which the specified value is associated
 169      * @param value value expected to be associated with the specified key
 170      * @return {@code true} if the value was removed
 171      * @throws UnsupportedOperationException if the {@code remove} operation
 172      *         is not supported by this map
 173      * @throws ClassCastException if the key or value is of an inappropriate
 174      *         type for this map
 175      *         (<a href="../Collection.html#optional-restrictions">optional</a>)
 176      * @throws NullPointerException if the specified key or value is null,
 177      *         and this map does not permit null keys or values
 178      *         (<a href="../Collection.html#optional-restrictions">optional</a>)
 179      */
 180     boolean remove(Object key, Object value);
 181 
 182     /**
 183      * Replaces the entry for a key only if currently mapped to a given value.
 184      * This is equivalent to
 185      *  <pre> {@code
 186      * if (map.containsKey(key) && Objects.equals(map.get(key), oldValue)) {
 187      *   map.put(key, newValue);
 188      *   return true;
 189      * } else
 190      *   return false;
 191      * }</pre>
 192      *
 193      * except that the action is performed atomically.
 194      *
 195      * @implNote This implementation intentionally re-abstracts the
 196      * inappropriate default provided in {@code Map}.
 197      *
 198      * @param key key with which the specified value is associated
 199      * @param oldValue value expected to be associated with the specified key
 200      * @param newValue value to be associated with the specified key
 201      * @return {@code true} if the value was replaced
 202      * @throws UnsupportedOperationException if the {@code put} operation
 203      *         is not supported by this map
 204      * @throws ClassCastException if the class of a specified key or value
 205      *         prevents it from being stored in this map
 206      * @throws NullPointerException if a specified key or value is null,
 207      *         and this map does not permit null keys or values
 208      * @throws IllegalArgumentException if some property of a specified key
 209      *         or value prevents it from being stored in this map
 210      */
 211     boolean replace(K key, V oldValue, V newValue);
 212 
 213     /**
 214      * Replaces the entry for a key only if currently mapped to some value.
 215      * This is equivalent to
 216      *  <pre> {@code
 217      * if (map.containsKey(key)) {
 218      *   return map.put(key, value);
 219      * } else
 220      *   return null;
 221      * }</pre>
 222      *
 223      * except that the action is performed atomically.
 224      *
 225      * @implNote This implementation intentionally re-abstracts the
 226      * inappropriate default provided in {@code Map}.
 227      *
 228      * @param key key with which the specified value is associated
 229      * @param value value to be associated with the specified key
 230      * @return the previous value associated with the specified key, or
 231      *         {@code null} if there was no mapping for the key.
 232      *         (A {@code null} return can also indicate that the map
 233      *         previously associated {@code null} with the key,
 234      *         if the implementation supports null values.)
 235      * @throws UnsupportedOperationException if the {@code put} operation
 236      *         is not supported by this map
 237      * @throws ClassCastException if the class of the specified key or value
 238      *         prevents it from being stored in this map
 239      * @throws NullPointerException if the specified key or value is null,
 240      *         and this map does not permit null keys or values
 241      * @throws IllegalArgumentException if some property of the specified key
 242      *         or value prevents it from being stored in this map
 243      */
 244     V replace(K key, V value);
 245 
 246     /**
 247      * {@inheritDoc}
 248      *
 249      * @implSpec
 250      * <p>The default implementation is equivalent to, for this {@code map}:
 251      * <pre> {@code
 252      * for ((Map.Entry<K, V> entry : map.entrySet())
 253      *     do {
 254      *        K k = entry.getKey();
 255      *        V v = entry.getValue();
 256      *     } while(!replace(k, v, function.apply(k, v)));
 257      * }</pre>
 258      *
 259      * The default implementation may retry these steps when multiple
 260      * threads attempt updates including potentially calling the function
 261      * repeatedly for a given key.
 262      *
 263      * <p>This implementation assumes that the ConcurrentMap cannot contain null
 264      * values and {@code get()} returning null unambiguously means the key is
 265      * absent. Implementations which support null values <strong>must</strong>
 266      * override this default implementation.
 267      *
 268      * @throws UnsupportedOperationException {@inheritDoc}
 269      * @throws NullPointerException {@inheritDoc}
 270      * @throws ClassCastException {@inheritDoc}
 271      * @throws IllegalArgumentException {@inheritDoc}
 272      * @since 1.8
 273      */
 274     @Override
 275     default void replaceAll(BiFunction<? super K, ? super V, ? extends V> function) {
 276         Objects.requireNonNull(function);
 277         forEach((k,v) -> {
 278             while(!replace(k, v, function.apply(k, v))) {
 279                 // v changed or k is gone
 280                 if ( (v = get(k)) == null) {
 281                     // k is no longer in the map.
 282                     break;
 283                 }
 284             }
 285         });
 286     }
 287 
 288     /**
 289      * {@inheritDoc}
 290      *
 291      * @implSpec
 292      * The default implementation is equivalent to the following steps for this
 293      * {@code map}, then returning the current value or {@code null} if now
 294      * absent:
 295      *
 296      * <pre> {@code
 297      * if (map.get(key) == null) {
 298      *     V newValue = mappingFunction.apply(key);
 299      *     if (newValue != null)
 300      *         return map.putIfAbsent(key, newValue);
 301      * }
 302      * }</pre>
 303      *
 304      * The default implementation may retry these steps when multiple
 305      * threads attempt updates including potentially calling the mapping
 306      * function multiple times.
 307      *
 308      * <p>This implementation assumes that the ConcurrentMap cannot contain null
 309      * values and {@code get()} returning null unambiguously means the key is
 310      * absent. Implementations which support null values <strong>must</strong>
 311      * override this default implementation.
 312      *
 313      * @throws UnsupportedOperationException {@inheritDoc}
 314      * @throws ClassCastException {@inheritDoc}
 315      * @throws NullPointerException {@inheritDoc}
 316      * @since 1.8
 317      */
 318     @Override
 319     default V computeIfAbsent(K key,
 320             Function<? super K, ? extends V> mappingFunction) {
 321         Objects.requireNonNull(mappingFunction);
 322         V v, newValue;
 323         return ((v = get(key)) == null &&
 324                 (newValue = mappingFunction.apply(key)) != null &&
 325                 (v = putIfAbsent(key, newValue)) == null) ? newValue : v;
 326     }
 327 
 328     /**
 329      * {@inheritDoc}
 330      *
 331      * @implSpec
 332      * The default implementation is equivalent to performing the following
 333      * steps for this {@code map}, then returning the current value or
 334      * {@code null} if now absent. :
 335      *
 336      * <pre> {@code
 337      * if (map.get(key) != null) {
 338      *     V oldValue = map.get(key);
 339      *     V newValue = remappingFunction.apply(key, oldValue);
 340      *     if (newValue != null)
 341      *         map.replace(key, oldValue, newValue);
 342      *     else
 343      *         map.remove(key, oldValue);
 344      * }
 345      * }</pre>
 346      *
 347      * The default implementation may retry these steps when multiple threads
 348      * attempt updates including potentially calling the remapping function
 349      * multiple times.
 350      *
 351      * <p>This implementation assumes that the ConcurrentMap cannot contain null
 352      * values and {@code get()} returning null unambiguously means the key is
 353      * absent. Implementations which support null values <strong>must</strong>
 354      * override this default implementation.
 355      *
 356      * @throws UnsupportedOperationException {@inheritDoc}
 357      * @throws ClassCastException {@inheritDoc}
 358      * @throws NullPointerException {@inheritDoc}
 359      * @since 1.8
 360      */
 361     @Override
 362     default V computeIfPresent(K key,
 363             BiFunction<? super K, ? super V, ? extends V> remappingFunction) {
 364         Objects.requireNonNull(remappingFunction);
 365         V oldValue;
 366         while((oldValue = get(key)) != null) {
 367             V newValue = remappingFunction.apply(key, oldValue);
 368             if (newValue != null) {
 369                 if (replace(key, oldValue, newValue))
 370                     return newValue;
 371             } else if (remove(key, oldValue))
 372                return null;
 373         }
 374         return oldValue;
 375     }
 376 
 377     /**
 378      * {@inheritDoc}
 379      *
 380      * @implSpec
 381      * The default implementation is equivalent to performing the following
 382      * steps for this {@code map}, then returning the current value or
 383      * {@code null} if absent:
 384      *
 385      * <pre> {@code
 386      * V oldValue = map.get(key);
 387      * V newValue = remappingFunction.apply(key, oldValue);
 388      * if (oldValue != null ) {
 389      *    if (newValue != null)
 390      *       map.replace(key, oldValue, newValue);
 391      *    else
 392      *       map.remove(key, oldValue);
 393      * } else {
 394      *    if (newValue != null)
 395      *       map.putIfAbsent(key, newValue);
 396      *    else
 397      *       return null;
 398      * }
 399      * }</pre>
 400      *
 401      * The default implementation may retry these steps when multiple
 402      * threads attempt updates including potentially calling the remapping
 403      * function multiple times.
 404      *
 405      * <p>This implementation assumes that the ConcurrentMap cannot contain null
 406      * values and {@code get()} returning null unambiguously means the key is
 407      * absent. Implementations which support null values <strong>must</strong>
 408      * override this default implementation.
 409      *
 410      * @throws UnsupportedOperationException {@inheritDoc}
 411      * @throws ClassCastException {@inheritDoc}
 412      * @throws NullPointerException {@inheritDoc}
 413      * @since 1.8
 414      */
 415     @Override
 416     default V compute(K key,
 417             BiFunction<? super K, ? super V, ? extends V> remappingFunction) {
 418         Objects.requireNonNull(remappingFunction);
 419         V oldValue = get(key);
 420         for(;;) {
 421             V newValue = remappingFunction.apply(key, oldValue);
 422             if (newValue == null) {
 423                 // delete mapping
 424                 if (oldValue != null || containsKey(key)) {
 425                     // something to remove
 426                     if (remove(key, oldValue)) {
 427                         // removed the old value as expected
 428                         return null;
 429                     }
 430 
 431                     // some other value replaced old value. try again.
 432                     oldValue = get(key);
 433                 } else {
 434                     // nothing to do. Leave things as they were.
 435                     return null;
 436                 }
 437             } else {
 438                 // add or replace old mapping
 439                 if (oldValue != null) {
 440                     // replace
 441                     if (replace(key, oldValue, newValue)) {
 442                         // replaced as expected.
 443                         return newValue;
 444                     }
 445 
 446                     // some other value replaced old value. try again.
 447                     oldValue = get(key);
 448                 } else {
 449                     // add (replace if oldValue was null)
 450                     if ((oldValue = putIfAbsent(key, newValue)) == null) {
 451                         // replaced
 452                         return newValue;
 453                     }
 454 
 455                     // some other value replaced old value. try again.
 456                 }
 457             }
 458         }
 459     }
 460 
 461 
 462     /**
 463      * {@inheritDoc}
 464      *
 465      * @implSpec
 466      * The default implementation is equivalent to performing the
 467      * following steps for this {@code map}, then returning the
 468      * current value or {@code null} if absent:
 469      *
 470      * <pre> {@code
 471      * V oldValue = map.get(key);
 472      * V newValue = (oldValue == null) ? value :
 473      *              remappingFunction.apply(oldValue, value);
 474      * if (newValue == null)
 475      *     map.remove(key);
 476      * else if (oldValue == null)
 477      *     map.remove(key);
 478      * else
 479      *     map.put(key, newValue);
 480      * }</pre>
 481      *
 482      * <p>The default implementation may retry these steps when multiple
 483      * threads attempt updates including potentially calling the remapping
 484      * function multiple times.
 485      *
 486      * <p>This implementation assumes that the ConcurrentMap cannot contain null
 487      * values and {@code get()} returning null unambiguously means the key is
 488      * absent. Implementations which support null values <strong>must</strong>
 489      * override this default implementation.
 490      *
 491      * @throws UnsupportedOperationException {@inheritDoc}
 492      * @throws ClassCastException {@inheritDoc}
 493      * @throws NullPointerException {@inheritDoc}
 494      * @since 1.8
 495      */
 496     @Override
 497     default V merge(K key, V value,
 498             BiFunction<? super V, ? super V, ? extends V> remappingFunction) {
 499         Objects.requireNonNull(remappingFunction);
 500         Objects.requireNonNull(value);
 501         V oldValue = get(key);
 502         for (;;) {
 503             if (oldValue != null) {
 504                 V newValue = remappingFunction.apply(oldValue, value);
 505                 if (newValue != null) {
 506                     if (replace(key, oldValue, newValue))
 507                         return newValue;
 508                 } else if (remove(key, oldValue)) {
 509                     return null;
 510                 }
 511                 oldValue = get(key);
 512             } else {
 513                 if ((oldValue = putIfAbsent(key, value)) == null) {
 514                     return value;
 515                 }
 516             }
 517         }
 518     }
 519 }