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