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