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 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 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: }