rt/emul/compact/src/main/java/java/util/concurrent/ConcurrentHashMap.java
author Jaroslav Tulach <jaroslav.tulach@apidesign.org>
Fri, 04 Oct 2013 10:52:01 +0200
changeset 1338 aa70afac4eca
parent 1334 588d5bf7a560
permissions -rw-r--r--
Concurrency utilities
     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 package java.util.concurrent;
    36 
    37 import java.util.*;
    38 import java.io.Serializable;
    39 import java.io.IOException;
    40 import java.io.ObjectInputStream;
    41 import java.io.ObjectOutputStream;
    42 
    43 /**
    44  * A hash table supporting full concurrency of retrievals and adjustable
    45  * expected concurrency for updates. This class obeys the same functional
    46  * specification as {@link java.util.Hashtable}, and includes versions of
    47  * methods corresponding to each method of
    48  * <tt>Hashtable</tt>. However, even though all operations are thread-safe,
    49  * retrieval operations do <em>not</em> entail locking, and there is
    50  * <em>not</em> any support for locking the entire table in a way that prevents
    51  * all access. This class is fully interoperable with <tt>Hashtable</tt> in
    52  * programs that rely on its thread safety but not on its synchronization
    53  * details.
    54  *
    55  * <p>
    56  * Retrieval operations (including <tt>get</tt>) generally do not block, so may
    57  * overlap with update operations (including
    58  * <tt>put</tt> and <tt>remove</tt>). Retrievals reflect the results of the most
    59  * recently <em>completed</em> update operations holding upon their onset. For
    60  * aggregate operations such as <tt>putAll</tt>
    61  * and <tt>clear</tt>, concurrent retrievals may reflect insertion or removal of
    62  * only some entries. Similarly, Iterators and Enumerations return elements
    63  * reflecting the state of the hash table at some point at or since the creation
    64  * of the iterator/enumeration. They do <em>not</em> throw
    65  * {@link ConcurrentModificationException}. However, iterators are designed to
    66  * be used by only one thread at a time.
    67  *
    68  * <p>
    69  * The allowed concurrency among update operations is guided by the optional
    70  * <tt>concurrencyLevel</tt> constructor argument (default <tt>16</tt>), which
    71  * is used as a hint for internal sizing. The table is internally partitioned to
    72  * try to permit the indicated number of concurrent updates without contention.
    73  * Because placement in hash tables is essentially random, the actual
    74  * concurrency will vary. Ideally, you should choose a value to accommodate as
    75  * many threads as will ever concurrently modify the table. Using a
    76  * significantly higher value than you need can waste space and time, and a
    77  * significantly lower value can lead to thread contention. But overestimates
    78  * and underestimates within an order of magnitude do not usually have much
    79  * noticeable impact. A value of one is appropriate when it is known that only
    80  * one thread will modify and all others will only read. Also, resizing this or
    81  * any other kind of hash table is a relatively slow operation, so, when
    82  * possible, it is a good idea to provide estimates of expected table sizes in
    83  * constructors.
    84  *
    85  * <p>
    86  * This class and its views and iterators implement all of the
    87  * <em>optional</em> methods of the {@link Map} and {@link Iterator} interfaces.
    88  *
    89  * <p>
    90  * Like {@link Hashtable} but unlike {@link HashMap}, this class does
    91  * <em>not</em> allow <tt>null</tt> to be used as a key or value.
    92  *
    93  * <p>
    94  * This class is a member of the
    95  * <a href="{@docRoot}/../technotes/guides/collections/index.html">
    96  * Java Collections Framework</a>.
    97  *
    98  * @since 1.5
    99  * @author Doug Lea
   100  * @param <K> the type of keys maintained by this map
   101  * @param <V> the type of mapped values
   102  */
   103 public class ConcurrentHashMap<K, V> extends AbstractMap<K, V>
   104     implements ConcurrentMap<K, V>, Serializable {
   105 
   106     private static final long serialVersionUID = 7249069246763182397L;
   107     /**
   108      * The default initial capacity for this table,
   109      * used when not otherwise specified in a constructor.
   110      */
   111     static final int DEFAULT_INITIAL_CAPACITY = 16;
   112 
   113     /**
   114      * The default load factor for this table, used when not
   115      * otherwise specified in a constructor.
   116      */
   117     static final float DEFAULT_LOAD_FACTOR = 0.75f;
   118 
   119     /**
   120      * The default concurrency level for this table, used when not
   121      * otherwise specified in a constructor.
   122      */
   123     static final int DEFAULT_CONCURRENCY_LEVEL = 16;
   124 
   125     private final Map<K, V> delegate;
   126 
   127 
   128     /**
   129      * Creates a new, empty map with the specified initial
   130      * capacity, load factor and concurrency level.
   131      *
   132      * @param initialCapacity the initial capacity. The implementation
   133      * performs internal sizing to accommodate this many elements.
   134      * @param loadFactor  the load factor threshold, used to control resizing.
   135      * Resizing may be performed when the average number of elements per
   136      * bin exceeds this threshold.
   137      * @param concurrencyLevel the estimated number of concurrently
   138      * updating threads. The implementation performs internal sizing
   139      * to try to accommodate this many threads.
   140      * @throws IllegalArgumentException if the initial capacity is
   141      * negative or the load factor or concurrencyLevel are
   142      * nonpositive.
   143      */
   144     @SuppressWarnings("unchecked")
   145     public ConcurrentHashMap(int initialCapacity,
   146                              float loadFactor, int concurrencyLevel) {
   147         if (!(loadFactor > 0) || initialCapacity < 0 || concurrencyLevel <= 0)
   148             throw new IllegalArgumentException();
   149         delegate = new HashMap<>(initialCapacity, loadFactor);
   150     }
   151 
   152     /**
   153      * Creates a new, empty map with the specified initial capacity
   154      * and load factor and with the default concurrencyLevel (16).
   155      *
   156      * @param initialCapacity The implementation performs internal
   157      * sizing to accommodate this many elements.
   158      * @param loadFactor  the load factor threshold, used to control resizing.
   159      * Resizing may be performed when the average number of elements per
   160      * bin exceeds this threshold.
   161      * @throws IllegalArgumentException if the initial capacity of
   162      * elements is negative or the load factor is nonpositive
   163      *
   164      * @since 1.6
   165      */
   166     public ConcurrentHashMap(int initialCapacity, float loadFactor) {
   167         this(initialCapacity, loadFactor, DEFAULT_CONCURRENCY_LEVEL);
   168     }
   169 
   170     /**
   171      * Creates a new, empty map with the specified initial capacity,
   172      * and with default load factor (0.75) and concurrencyLevel (16).
   173      *
   174      * @param initialCapacity the initial capacity. The implementation
   175      * performs internal sizing to accommodate this many elements.
   176      * @throws IllegalArgumentException if the initial capacity of
   177      * elements is negative.
   178      */
   179     public ConcurrentHashMap(int initialCapacity) {
   180         this(initialCapacity, DEFAULT_LOAD_FACTOR, DEFAULT_CONCURRENCY_LEVEL);
   181     }
   182 
   183     /**
   184      * Creates a new, empty map with a default initial capacity (16),
   185      * load factor (0.75) and concurrencyLevel (16).
   186      */
   187     public ConcurrentHashMap() {
   188         this(DEFAULT_INITIAL_CAPACITY, DEFAULT_LOAD_FACTOR, DEFAULT_CONCURRENCY_LEVEL);
   189     }
   190 
   191     /**
   192      * Creates a new map with the same mappings as the given map.
   193      * The map is created with a capacity of 1.5 times the number
   194      * of mappings in the given map or 16 (whichever is greater),
   195      * and a default load factor (0.75) and concurrencyLevel (16).
   196      *
   197      * @param m the map
   198      */
   199     public ConcurrentHashMap(Map<? extends K, ? extends V> m) {
   200         this(Math.max((int) (m.size() / DEFAULT_LOAD_FACTOR) + 1,
   201                       DEFAULT_INITIAL_CAPACITY),
   202              DEFAULT_LOAD_FACTOR, DEFAULT_CONCURRENCY_LEVEL);
   203         putAll(m);
   204     }
   205     
   206 
   207     @Override
   208     public int size() {
   209         return delegate.size();
   210     }
   211 
   212     @Override
   213     public boolean isEmpty() {
   214         return delegate.isEmpty();
   215     }
   216 
   217     @Override
   218     public boolean containsKey(Object key) {
   219         return delegate.containsKey(key);
   220     }
   221 
   222     @Override
   223     public boolean containsValue(Object value) {
   224         return delegate.containsValue(value);
   225     }
   226 
   227     @Override
   228     public V get(Object key) {
   229         return delegate.get(key);
   230     }
   231 
   232     @Override
   233     public V put(K key, V value) {
   234         return delegate.put(key, value);
   235     }
   236 
   237     @Override
   238     public V remove(Object key) {
   239         return delegate.remove(key);
   240     }
   241 
   242     @Override
   243     public void putAll(Map<? extends K, ? extends V> m) {
   244         delegate.putAll(m);
   245     }
   246 
   247     @Override
   248     public void clear() {
   249         delegate.clear();
   250     }
   251 
   252     @Override
   253     public Set<K> keySet() {
   254         return delegate.keySet();
   255     }
   256 
   257     @Override
   258     public Collection<V> values() {
   259         return delegate.values();
   260     }
   261 
   262     @Override
   263     public Set<Entry<K, V>> entrySet() {
   264         return delegate.entrySet();
   265     }
   266 
   267     @Override
   268     public boolean equals(Object o) {
   269         return delegate.equals(o);
   270     }
   271 
   272     @Override
   273     public int hashCode() {
   274         return delegate.hashCode();
   275     }
   276 
   277     @Override
   278     public String toString() {
   279         return delegate.toString();
   280     }
   281 
   282     @Override
   283     public V putIfAbsent(K key, V value) {
   284         V old = delegate.get(key);
   285         if (old == null) {
   286             return delegate.put(key, value);
   287         }
   288         return old;
   289     }
   290 
   291     @Override
   292     public boolean remove(Object key, Object value) {
   293         if (equals(value, delegate.get(key))) {
   294             delegate.remove(key);
   295             return true;
   296         } else {
   297             return false;
   298         }
   299     }
   300 
   301     @Override
   302     public boolean replace(K key, V oldValue, V newValue) {
   303         if (equals(oldValue, delegate.get(key))) {
   304             delegate.put(key, newValue);
   305             return true;
   306         } else {
   307             return false;
   308         }
   309     }
   310 
   311     @Override
   312     public V replace(K key, V value) {
   313         if (delegate.containsKey(key)) {
   314             return delegate.put(key, value);
   315         } else {
   316             return null;
   317         }
   318     }
   319     
   320     private static boolean equals(Object a, Object b) {
   321         if (a == null) {
   322             return b == null;
   323         } else {
   324             return a.equals(b);
   325         }
   326     }
   327 }