jtulach@1334: /*
jtulach@1334: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
jtulach@1334: *
jtulach@1334: * This code is free software; you can redistribute it and/or modify it
jtulach@1334: * under the terms of the GNU General Public License version 2 only, as
jtulach@1334: * published by the Free Software Foundation. Oracle designates this
jtulach@1334: * particular file as subject to the "Classpath" exception as provided
jtulach@1334: * by Oracle in the LICENSE file that accompanied this code.
jtulach@1334: *
jtulach@1334: * This code is distributed in the hope that it will be useful, but WITHOUT
jtulach@1334: * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
jtulach@1334: * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
jtulach@1334: * version 2 for more details (a copy is included in the LICENSE file that
jtulach@1334: * accompanied this code).
jtulach@1334: *
jtulach@1334: * You should have received a copy of the GNU General Public License version
jtulach@1334: * 2 along with this work; if not, write to the Free Software Foundation,
jtulach@1334: * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
jtulach@1334: *
jtulach@1334: * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
jtulach@1334: * or visit www.oracle.com if you need additional information or have any
jtulach@1334: * questions.
jtulach@1334: */
jtulach@1334:
jtulach@1334: /*
jtulach@1334: * This file is available under and governed by the GNU General Public
jtulach@1334: * License version 2 only, as published by the Free Software Foundation.
jtulach@1334: * However, the following notice accompanied the original version of this
jtulach@1334: * file:
jtulach@1334: *
jtulach@1334: * Written by Doug Lea with assistance from members of JCP JSR-166
jtulach@1334: * Expert Group and released to the public domain, as explained at
jtulach@1334: * http://creativecommons.org/publicdomain/zero/1.0/
jtulach@1334: */
jaroslav@1338: package java.util.concurrent;
jtulach@1334:
jtulach@1334: import java.util.*;
jtulach@1334: import java.io.Serializable;
jtulach@1334: import java.io.IOException;
jtulach@1334: import java.io.ObjectInputStream;
jtulach@1334: import java.io.ObjectOutputStream;
jtulach@1334:
jtulach@1334: /**
jaroslav@1338: * A hash table supporting full concurrency of retrievals and adjustable
jaroslav@1338: * expected concurrency for updates. This class obeys the same functional
jaroslav@1338: * specification as {@link java.util.Hashtable}, and includes versions of
jaroslav@1338: * methods corresponding to each method of
jaroslav@1338: * Hashtable. However, even though all operations are thread-safe,
jaroslav@1338: * retrieval operations do not entail locking, and there is
jaroslav@1338: * not any support for locking the entire table in a way that prevents
jaroslav@1338: * all access. This class is fully interoperable with Hashtable in
jaroslav@1338: * programs that rely on its thread safety but not on its synchronization
jaroslav@1338: * details.
jtulach@1334: *
jaroslav@1338: *
jaroslav@1338: * Retrieval operations (including get) generally do not block, so may
jaroslav@1338: * overlap with update operations (including
jaroslav@1338: * put and remove). Retrievals reflect the results of the most
jaroslav@1338: * recently completed update operations holding upon their onset. For
jaroslav@1338: * aggregate operations such as putAll
jaroslav@1338: * and clear, concurrent retrievals may reflect insertion or removal of
jaroslav@1338: * only some entries. Similarly, Iterators and Enumerations return elements
jaroslav@1338: * reflecting the state of the hash table at some point at or since the creation
jaroslav@1338: * of the iterator/enumeration. They do not throw
jaroslav@1338: * {@link ConcurrentModificationException}. However, iterators are designed to
jaroslav@1338: * be used by only one thread at a time.
jtulach@1334: *
jaroslav@1338: *
jaroslav@1338: * The allowed concurrency among update operations is guided by the optional
jaroslav@1338: * concurrencyLevel constructor argument (default 16), which
jaroslav@1338: * is used as a hint for internal sizing. The table is internally partitioned to
jaroslav@1338: * try to permit the indicated number of concurrent updates without contention.
jaroslav@1338: * Because placement in hash tables is essentially random, the actual
jaroslav@1338: * concurrency will vary. Ideally, you should choose a value to accommodate as
jaroslav@1338: * many threads as will ever concurrently modify the table. Using a
jaroslav@1338: * significantly higher value than you need can waste space and time, and a
jaroslav@1338: * significantly lower value can lead to thread contention. But overestimates
jaroslav@1338: * and underestimates within an order of magnitude do not usually have much
jaroslav@1338: * noticeable impact. A value of one is appropriate when it is known that only
jaroslav@1338: * one thread will modify and all others will only read. Also, resizing this or
jaroslav@1338: * any other kind of hash table is a relatively slow operation, so, when
jaroslav@1338: * possible, it is a good idea to provide estimates of expected table sizes in
jtulach@1334: * constructors.
jtulach@1334: *
jaroslav@1338: *
jaroslav@1338: * This class and its views and iterators implement all of the
jaroslav@1338: * optional methods of the {@link Map} and {@link Iterator} interfaces.
jtulach@1334: *
jaroslav@1338: *
jaroslav@1338: * Like {@link Hashtable} but unlike {@link HashMap}, this class does
jaroslav@1338: * not allow null to be used as a key or value.
jtulach@1334: *
jaroslav@1338: *
jaroslav@1338: * This class is a member of the
jtulach@1334: *
jtulach@1334: * Java Collections Framework.
jtulach@1334: *
jtulach@1334: * @since 1.5
jtulach@1334: * @author Doug Lea
jtulach@1334: * @param the type of keys maintained by this map
jtulach@1334: * @param the type of mapped values
jtulach@1334: */
jtulach@1334: public class ConcurrentHashMap extends AbstractMap
jaroslav@1338: implements ConcurrentMap, Serializable {
jaroslav@1338:
jtulach@1334: private static final long serialVersionUID = 7249069246763182397L;
jtulach@1334: /**
jtulach@1334: * The default initial capacity for this table,
jtulach@1334: * used when not otherwise specified in a constructor.
jtulach@1334: */
jtulach@1334: static final int DEFAULT_INITIAL_CAPACITY = 16;
jtulach@1334:
jtulach@1334: /**
jtulach@1334: * The default load factor for this table, used when not
jtulach@1334: * otherwise specified in a constructor.
jtulach@1334: */
jtulach@1334: static final float DEFAULT_LOAD_FACTOR = 0.75f;
jtulach@1334:
jtulach@1334: /**
jtulach@1334: * The default concurrency level for this table, used when not
jtulach@1334: * otherwise specified in a constructor.
jtulach@1334: */
jtulach@1334: static final int DEFAULT_CONCURRENCY_LEVEL = 16;
jtulach@1334:
jaroslav@1338: private final Map delegate;
jtulach@1334:
jtulach@1334:
jtulach@1334: /**
jtulach@1334: * Creates a new, empty map with the specified initial
jtulach@1334: * capacity, load factor and concurrency level.
jtulach@1334: *
jtulach@1334: * @param initialCapacity the initial capacity. The implementation
jtulach@1334: * performs internal sizing to accommodate this many elements.
jtulach@1334: * @param loadFactor the load factor threshold, used to control resizing.
jtulach@1334: * Resizing may be performed when the average number of elements per
jtulach@1334: * bin exceeds this threshold.
jtulach@1334: * @param concurrencyLevel the estimated number of concurrently
jtulach@1334: * updating threads. The implementation performs internal sizing
jtulach@1334: * to try to accommodate this many threads.
jtulach@1334: * @throws IllegalArgumentException if the initial capacity is
jtulach@1334: * negative or the load factor or concurrencyLevel are
jtulach@1334: * nonpositive.
jtulach@1334: */
jtulach@1334: @SuppressWarnings("unchecked")
jtulach@1334: public ConcurrentHashMap(int initialCapacity,
jtulach@1334: float loadFactor, int concurrencyLevel) {
jtulach@1334: if (!(loadFactor > 0) || initialCapacity < 0 || concurrencyLevel <= 0)
jtulach@1334: throw new IllegalArgumentException();
jaroslav@1338: delegate = new HashMap<>(initialCapacity, loadFactor);
jtulach@1334: }
jtulach@1334:
jtulach@1334: /**
jtulach@1334: * Creates a new, empty map with the specified initial capacity
jtulach@1334: * and load factor and with the default concurrencyLevel (16).
jtulach@1334: *
jtulach@1334: * @param initialCapacity The implementation performs internal
jtulach@1334: * sizing to accommodate this many elements.
jtulach@1334: * @param loadFactor the load factor threshold, used to control resizing.
jtulach@1334: * Resizing may be performed when the average number of elements per
jtulach@1334: * bin exceeds this threshold.
jtulach@1334: * @throws IllegalArgumentException if the initial capacity of
jtulach@1334: * elements is negative or the load factor is nonpositive
jtulach@1334: *
jtulach@1334: * @since 1.6
jtulach@1334: */
jtulach@1334: public ConcurrentHashMap(int initialCapacity, float loadFactor) {
jtulach@1334: this(initialCapacity, loadFactor, DEFAULT_CONCURRENCY_LEVEL);
jtulach@1334: }
jtulach@1334:
jtulach@1334: /**
jtulach@1334: * Creates a new, empty map with the specified initial capacity,
jtulach@1334: * and with default load factor (0.75) and concurrencyLevel (16).
jtulach@1334: *
jtulach@1334: * @param initialCapacity the initial capacity. The implementation
jtulach@1334: * performs internal sizing to accommodate this many elements.
jtulach@1334: * @throws IllegalArgumentException if the initial capacity of
jtulach@1334: * elements is negative.
jtulach@1334: */
jtulach@1334: public ConcurrentHashMap(int initialCapacity) {
jtulach@1334: this(initialCapacity, DEFAULT_LOAD_FACTOR, DEFAULT_CONCURRENCY_LEVEL);
jtulach@1334: }
jtulach@1334:
jtulach@1334: /**
jtulach@1334: * Creates a new, empty map with a default initial capacity (16),
jtulach@1334: * load factor (0.75) and concurrencyLevel (16).
jtulach@1334: */
jtulach@1334: public ConcurrentHashMap() {
jtulach@1334: this(DEFAULT_INITIAL_CAPACITY, DEFAULT_LOAD_FACTOR, DEFAULT_CONCURRENCY_LEVEL);
jtulach@1334: }
jtulach@1334:
jtulach@1334: /**
jtulach@1334: * Creates a new map with the same mappings as the given map.
jtulach@1334: * The map is created with a capacity of 1.5 times the number
jtulach@1334: * of mappings in the given map or 16 (whichever is greater),
jtulach@1334: * and a default load factor (0.75) and concurrencyLevel (16).
jtulach@1334: *
jtulach@1334: * @param m the map
jtulach@1334: */
jtulach@1334: public ConcurrentHashMap(Map extends K, ? extends V> m) {
jtulach@1334: this(Math.max((int) (m.size() / DEFAULT_LOAD_FACTOR) + 1,
jtulach@1334: DEFAULT_INITIAL_CAPACITY),
jtulach@1334: DEFAULT_LOAD_FACTOR, DEFAULT_CONCURRENCY_LEVEL);
jtulach@1334: putAll(m);
jtulach@1334: }
jaroslav@1338:
jtulach@1334:
jaroslav@1338: @Override
jaroslav@1338: public int size() {
jaroslav@1338: return delegate.size();
jtulach@1334: }
jtulach@1334:
jaroslav@1338: @Override
jaroslav@1338: public boolean isEmpty() {
jaroslav@1338: return delegate.isEmpty();
jtulach@1334: }
jtulach@1334:
jaroslav@1338: @Override
jaroslav@1338: public boolean containsKey(Object key) {
jaroslav@1338: return delegate.containsKey(key);
jtulach@1334: }
jtulach@1334:
jaroslav@1338: @Override
jaroslav@1338: public boolean containsValue(Object value) {
jaroslav@1338: return delegate.containsValue(value);
jtulach@1334: }
jtulach@1334:
jaroslav@1338: @Override
jaroslav@1338: public V get(Object key) {
jaroslav@1338: return delegate.get(key);
jtulach@1334: }
jtulach@1334:
jaroslav@1338: @Override
jaroslav@1338: public V put(K key, V value) {
jaroslav@1338: return delegate.put(key, value);
jtulach@1334: }
jtulach@1334:
jaroslav@1338: @Override
jaroslav@1338: public V remove(Object key) {
jaroslav@1338: return delegate.remove(key);
jtulach@1334: }
jtulach@1334:
jaroslav@1338: @Override
jaroslav@1338: public void putAll(Map extends K, ? extends V> m) {
jaroslav@1338: delegate.putAll(m);
jtulach@1334: }
jtulach@1334:
jaroslav@1338: @Override
jaroslav@1338: public void clear() {
jaroslav@1338: delegate.clear();
jtulach@1334: }
jtulach@1334:
jaroslav@1338: @Override
jaroslav@1338: public Set keySet() {
jaroslav@1338: return delegate.keySet();
jtulach@1334: }
jtulach@1334:
jaroslav@1338: @Override
jaroslav@1338: public Collection values() {
jaroslav@1338: return delegate.values();
jtulach@1334: }
jtulach@1334:
jaroslav@1338: @Override
jaroslav@1338: public Set> entrySet() {
jaroslav@1338: return delegate.entrySet();
jtulach@1334: }
jtulach@1334:
jaroslav@1338: @Override
jaroslav@1338: public boolean equals(Object o) {
jaroslav@1338: return delegate.equals(o);
jtulach@1334: }
jtulach@1334:
jaroslav@1338: @Override
jaroslav@1338: public int hashCode() {
jaroslav@1338: return delegate.hashCode();
jaroslav@1338: }
jaroslav@1338:
jaroslav@1338: @Override
jaroslav@1338: public String toString() {
jaroslav@1338: return delegate.toString();
jaroslav@1338: }
jaroslav@1338:
jaroslav@1338: @Override
jaroslav@1338: public V putIfAbsent(K key, V value) {
jaroslav@1338: V old = delegate.get(key);
jaroslav@1338: if (old == null) {
jaroslav@1338: return delegate.put(key, value);
jaroslav@1338: }
jaroslav@1338: return old;
jaroslav@1338: }
jaroslav@1338:
jaroslav@1338: @Override
jaroslav@1338: public boolean remove(Object key, Object value) {
jaroslav@1338: if (equals(value, delegate.get(key))) {
jaroslav@1338: delegate.remove(key);
jaroslav@1338: return true;
jaroslav@1338: } else {
jaroslav@1338: return false;
jtulach@1334: }
jtulach@1334: }
jtulach@1334:
jaroslav@1338: @Override
jaroslav@1338: public boolean replace(K key, V oldValue, V newValue) {
jaroslav@1338: if (equals(oldValue, delegate.get(key))) {
jaroslav@1338: delegate.put(key, newValue);
jaroslav@1338: return true;
jaroslav@1338: } else {
jaroslav@1338: return false;
jtulach@1334: }
jtulach@1334: }
jtulach@1334:
jaroslav@1338: @Override
jaroslav@1338: public V replace(K key, V value) {
jaroslav@1338: if (delegate.containsKey(key)) {
jaroslav@1338: return delegate.put(key, value);
jaroslav@1338: } else {
jaroslav@1338: return null;
jtulach@1334: }
jtulach@1334: }
jaroslav@1338:
jaroslav@1338: private static boolean equals(Object a, Object b) {
jaroslav@1338: if (a == null) {
jaroslav@1338: return b == null;
jaroslav@1338: } else {
jaroslav@1338: return a.equals(b);
jtulach@1334: }
jtulach@1334: }
jtulach@1334: }