1.1 --- a/rt/emul/compact/src/main/java/java/util/concurrent/ConcurrentHashMap.java Thu Oct 03 17:36:44 2013 +0200
1.2 +++ b/rt/emul/compact/src/main/java/java/util/concurrent/ConcurrentHashMap.java Fri Oct 04 10:52:01 2013 +0200
1.3 @@ -32,9 +32,8 @@
1.4 * Expert Group and released to the public domain, as explained at
1.5 * http://creativecommons.org/publicdomain/zero/1.0/
1.6 */
1.7 +package java.util.concurrent;
1.8
1.9 -package java.util.concurrent;
1.10 -import java.util.concurrent.locks.*;
1.11 import java.util.*;
1.12 import java.io.Serializable;
1.13 import java.io.IOException;
1.14 @@ -42,55 +41,57 @@
1.15 import java.io.ObjectOutputStream;
1.16
1.17 /**
1.18 - * A hash table supporting full concurrency of retrievals and
1.19 - * adjustable expected concurrency for updates. This class obeys the
1.20 - * same functional specification as {@link java.util.Hashtable}, and
1.21 - * includes versions of methods corresponding to each method of
1.22 - * <tt>Hashtable</tt>. However, even though all operations are
1.23 - * thread-safe, retrieval operations do <em>not</em> entail locking,
1.24 - * and there is <em>not</em> any support for locking the entire table
1.25 - * in a way that prevents all access. This class is fully
1.26 - * interoperable with <tt>Hashtable</tt> in programs that rely on its
1.27 - * thread safety but not on its synchronization details.
1.28 + * A hash table supporting full concurrency of retrievals and adjustable
1.29 + * expected concurrency for updates. This class obeys the same functional
1.30 + * specification as {@link java.util.Hashtable}, and includes versions of
1.31 + * methods corresponding to each method of
1.32 + * <tt>Hashtable</tt>. However, even though all operations are thread-safe,
1.33 + * retrieval operations do <em>not</em> entail locking, and there is
1.34 + * <em>not</em> any support for locking the entire table in a way that prevents
1.35 + * all access. This class is fully interoperable with <tt>Hashtable</tt> in
1.36 + * programs that rely on its thread safety but not on its synchronization
1.37 + * details.
1.38 *
1.39 - * <p> Retrieval operations (including <tt>get</tt>) generally do not
1.40 - * block, so may overlap with update operations (including
1.41 - * <tt>put</tt> and <tt>remove</tt>). Retrievals reflect the results
1.42 - * of the most recently <em>completed</em> update operations holding
1.43 - * upon their onset. For aggregate operations such as <tt>putAll</tt>
1.44 - * and <tt>clear</tt>, concurrent retrievals may reflect insertion or
1.45 - * removal of only some entries. Similarly, Iterators and
1.46 - * Enumerations return elements reflecting the state of the hash table
1.47 - * at some point at or since the creation of the iterator/enumeration.
1.48 - * They do <em>not</em> throw {@link ConcurrentModificationException}.
1.49 - * However, iterators are designed to be used by only one thread at a time.
1.50 + * <p>
1.51 + * Retrieval operations (including <tt>get</tt>) generally do not block, so may
1.52 + * overlap with update operations (including
1.53 + * <tt>put</tt> and <tt>remove</tt>). Retrievals reflect the results of the most
1.54 + * recently <em>completed</em> update operations holding upon their onset. For
1.55 + * aggregate operations such as <tt>putAll</tt>
1.56 + * and <tt>clear</tt>, concurrent retrievals may reflect insertion or removal of
1.57 + * only some entries. Similarly, Iterators and Enumerations return elements
1.58 + * reflecting the state of the hash table at some point at or since the creation
1.59 + * of the iterator/enumeration. They do <em>not</em> throw
1.60 + * {@link ConcurrentModificationException}. However, iterators are designed to
1.61 + * be used by only one thread at a time.
1.62 *
1.63 - * <p> The allowed concurrency among update operations is guided by
1.64 - * the optional <tt>concurrencyLevel</tt> constructor argument
1.65 - * (default <tt>16</tt>), which is used as a hint for internal sizing. The
1.66 - * table is internally partitioned to try to permit the indicated
1.67 - * number of concurrent updates without contention. Because placement
1.68 - * in hash tables is essentially random, the actual concurrency will
1.69 - * vary. Ideally, you should choose a value to accommodate as many
1.70 - * threads as will ever concurrently modify the table. Using a
1.71 - * significantly higher value than you need can waste space and time,
1.72 - * and a significantly lower value can lead to thread contention. But
1.73 - * overestimates and underestimates within an order of magnitude do
1.74 - * not usually have much noticeable impact. A value of one is
1.75 - * appropriate when it is known that only one thread will modify and
1.76 - * all others will only read. Also, resizing this or any other kind of
1.77 - * hash table is a relatively slow operation, so, when possible, it is
1.78 - * a good idea to provide estimates of expected table sizes in
1.79 + * <p>
1.80 + * The allowed concurrency among update operations is guided by the optional
1.81 + * <tt>concurrencyLevel</tt> constructor argument (default <tt>16</tt>), which
1.82 + * is used as a hint for internal sizing. The table is internally partitioned to
1.83 + * try to permit the indicated number of concurrent updates without contention.
1.84 + * Because placement in hash tables is essentially random, the actual
1.85 + * concurrency will vary. Ideally, you should choose a value to accommodate as
1.86 + * many threads as will ever concurrently modify the table. Using a
1.87 + * significantly higher value than you need can waste space and time, and a
1.88 + * significantly lower value can lead to thread contention. But overestimates
1.89 + * and underestimates within an order of magnitude do not usually have much
1.90 + * noticeable impact. A value of one is appropriate when it is known that only
1.91 + * one thread will modify and all others will only read. Also, resizing this or
1.92 + * any other kind of hash table is a relatively slow operation, so, when
1.93 + * possible, it is a good idea to provide estimates of expected table sizes in
1.94 * constructors.
1.95 *
1.96 - * <p>This class and its views and iterators implement all of the
1.97 - * <em>optional</em> methods of the {@link Map} and {@link Iterator}
1.98 - * interfaces.
1.99 + * <p>
1.100 + * This class and its views and iterators implement all of the
1.101 + * <em>optional</em> methods of the {@link Map} and {@link Iterator} interfaces.
1.102 *
1.103 - * <p> Like {@link Hashtable} but unlike {@link HashMap}, this class
1.104 - * does <em>not</em> allow <tt>null</tt> to be used as a key or value.
1.105 + * <p>
1.106 + * Like {@link Hashtable} but unlike {@link HashMap}, this class does
1.107 + * <em>not</em> allow <tt>null</tt> to be used as a key or value.
1.108 *
1.109 - * <p>This class is a member of the
1.110 + * <p>
1.111 + * This class is a member of the
1.112 * <a href="{@docRoot}/../technotes/guides/collections/index.html">
1.113 * Java Collections Framework</a>.
1.114 *
1.115 @@ -100,34 +101,9 @@
1.116 * @param <V> the type of mapped values
1.117 */
1.118 public class ConcurrentHashMap<K, V> extends AbstractMap<K, V>
1.119 - implements ConcurrentMap<K, V>, Serializable {
1.120 + implements ConcurrentMap<K, V>, Serializable {
1.121 +
1.122 private static final long serialVersionUID = 7249069246763182397L;
1.123 -
1.124 - /*
1.125 - * The basic strategy is to subdivide the table among Segments,
1.126 - * each of which itself is a concurrently readable hash table. To
1.127 - * reduce footprint, all but one segments are constructed only
1.128 - * when first needed (see ensureSegment). To maintain visibility
1.129 - * in the presence of lazy construction, accesses to segments as
1.130 - * well as elements of segment's table must use volatile access,
1.131 - * which is done via Unsafe within methods segmentAt etc
1.132 - * below. These provide the functionality of AtomicReferenceArrays
1.133 - * but reduce the levels of indirection. Additionally,
1.134 - * volatile-writes of table elements and entry "next" fields
1.135 - * within locked operations use the cheaper "lazySet" forms of
1.136 - * writes (via putOrderedObject) because these writes are always
1.137 - * followed by lock releases that maintain sequential consistency
1.138 - * of table updates.
1.139 - *
1.140 - * Historical note: The previous version of this class relied
1.141 - * heavily on "final" fields, which avoided some volatile reads at
1.142 - * the expense of a large initial footprint. Some remnants of
1.143 - * that design (including forced construction of segment 0) exist
1.144 - * to ensure serialization compatibility.
1.145 - */
1.146 -
1.147 - /* ---------------- Constants -------------- */
1.148 -
1.149 /**
1.150 * The default initial capacity for this table,
1.151 * used when not otherwise specified in a constructor.
1.152 @@ -146,574 +122,8 @@
1.153 */
1.154 static final int DEFAULT_CONCURRENCY_LEVEL = 16;
1.155
1.156 - /**
1.157 - * The maximum capacity, used if a higher value is implicitly
1.158 - * specified by either of the constructors with arguments. MUST
1.159 - * be a power of two <= 1<<30 to ensure that entries are indexable
1.160 - * using ints.
1.161 - */
1.162 - static final int MAXIMUM_CAPACITY = 1 << 30;
1.163 + private final Map<K, V> delegate;
1.164
1.165 - /**
1.166 - * The minimum capacity for per-segment tables. Must be a power
1.167 - * of two, at least two to avoid immediate resizing on next use
1.168 - * after lazy construction.
1.169 - */
1.170 - static final int MIN_SEGMENT_TABLE_CAPACITY = 2;
1.171 -
1.172 - /**
1.173 - * The maximum number of segments to allow; used to bound
1.174 - * constructor arguments. Must be power of two less than 1 << 24.
1.175 - */
1.176 - static final int MAX_SEGMENTS = 1 << 16; // slightly conservative
1.177 -
1.178 - /**
1.179 - * Number of unsynchronized retries in size and containsValue
1.180 - * methods before resorting to locking. This is used to avoid
1.181 - * unbounded retries if tables undergo continuous modification
1.182 - * which would make it impossible to obtain an accurate result.
1.183 - */
1.184 - static final int RETRIES_BEFORE_LOCK = 2;
1.185 -
1.186 - /* ---------------- Fields -------------- */
1.187 -
1.188 - /**
1.189 - * Mask value for indexing into segments. The upper bits of a
1.190 - * key's hash code are used to choose the segment.
1.191 - */
1.192 - final int segmentMask;
1.193 -
1.194 - /**
1.195 - * Shift value for indexing within segments.
1.196 - */
1.197 - final int segmentShift;
1.198 -
1.199 - /**
1.200 - * The segments, each of which is a specialized hash table.
1.201 - */
1.202 - final Segment<K,V>[] segments;
1.203 -
1.204 - transient Set<K> keySet;
1.205 - transient Set<Map.Entry<K,V>> entrySet;
1.206 - transient Collection<V> values;
1.207 -
1.208 - /**
1.209 - * ConcurrentHashMap list entry. Note that this is never exported
1.210 - * out as a user-visible Map.Entry.
1.211 - */
1.212 - static final class HashEntry<K,V> {
1.213 - final int hash;
1.214 - final K key;
1.215 - volatile V value;
1.216 - volatile HashEntry<K,V> next;
1.217 -
1.218 - HashEntry(int hash, K key, V value, HashEntry<K,V> next) {
1.219 - this.hash = hash;
1.220 - this.key = key;
1.221 - this.value = value;
1.222 - this.next = next;
1.223 - }
1.224 -
1.225 - /**
1.226 - * Sets next field with volatile write semantics. (See above
1.227 - * about use of putOrderedObject.)
1.228 - */
1.229 - final void setNext(HashEntry<K,V> n) {
1.230 - UNSAFE.putOrderedObject(this, nextOffset, n);
1.231 - }
1.232 -
1.233 - // Unsafe mechanics
1.234 - static final sun.misc.Unsafe UNSAFE;
1.235 - static final long nextOffset;
1.236 - static {
1.237 - try {
1.238 - UNSAFE = sun.misc.Unsafe.getUnsafe();
1.239 - Class k = HashEntry.class;
1.240 - nextOffset = UNSAFE.objectFieldOffset
1.241 - (k.getDeclaredField("next"));
1.242 - } catch (Exception e) {
1.243 - throw new Error(e);
1.244 - }
1.245 - }
1.246 - }
1.247 -
1.248 - /**
1.249 - * Gets the ith element of given table (if nonnull) with volatile
1.250 - * read semantics. Note: This is manually integrated into a few
1.251 - * performance-sensitive methods to reduce call overhead.
1.252 - */
1.253 - @SuppressWarnings("unchecked")
1.254 - static final <K,V> HashEntry<K,V> entryAt(HashEntry<K,V>[] tab, int i) {
1.255 - return (tab == null) ? null :
1.256 - (HashEntry<K,V>) UNSAFE.getObjectVolatile
1.257 - (tab, ((long)i << TSHIFT) + TBASE);
1.258 - }
1.259 -
1.260 - /**
1.261 - * Sets the ith element of given table, with volatile write
1.262 - * semantics. (See above about use of putOrderedObject.)
1.263 - */
1.264 - static final <K,V> void setEntryAt(HashEntry<K,V>[] tab, int i,
1.265 - HashEntry<K,V> e) {
1.266 - UNSAFE.putOrderedObject(tab, ((long)i << TSHIFT) + TBASE, e);
1.267 - }
1.268 -
1.269 - /**
1.270 - * Applies a supplemental hash function to a given hashCode, which
1.271 - * defends against poor quality hash functions. This is critical
1.272 - * because ConcurrentHashMap uses power-of-two length hash tables,
1.273 - * that otherwise encounter collisions for hashCodes that do not
1.274 - * differ in lower or upper bits.
1.275 - */
1.276 - private static int hash(int h) {
1.277 - // Spread bits to regularize both segment and index locations,
1.278 - // using variant of single-word Wang/Jenkins hash.
1.279 - h += (h << 15) ^ 0xffffcd7d;
1.280 - h ^= (h >>> 10);
1.281 - h += (h << 3);
1.282 - h ^= (h >>> 6);
1.283 - h += (h << 2) + (h << 14);
1.284 - return h ^ (h >>> 16);
1.285 - }
1.286 -
1.287 - /**
1.288 - * Segments are specialized versions of hash tables. This
1.289 - * subclasses from ReentrantLock opportunistically, just to
1.290 - * simplify some locking and avoid separate construction.
1.291 - */
1.292 - static final class Segment<K,V> extends ReentrantLock implements Serializable {
1.293 - /*
1.294 - * Segments maintain a table of entry lists that are always
1.295 - * kept in a consistent state, so can be read (via volatile
1.296 - * reads of segments and tables) without locking. This
1.297 - * requires replicating nodes when necessary during table
1.298 - * resizing, so the old lists can be traversed by readers
1.299 - * still using old version of table.
1.300 - *
1.301 - * This class defines only mutative methods requiring locking.
1.302 - * Except as noted, the methods of this class perform the
1.303 - * per-segment versions of ConcurrentHashMap methods. (Other
1.304 - * methods are integrated directly into ConcurrentHashMap
1.305 - * methods.) These mutative methods use a form of controlled
1.306 - * spinning on contention via methods scanAndLock and
1.307 - * scanAndLockForPut. These intersperse tryLocks with
1.308 - * traversals to locate nodes. The main benefit is to absorb
1.309 - * cache misses (which are very common for hash tables) while
1.310 - * obtaining locks so that traversal is faster once
1.311 - * acquired. We do not actually use the found nodes since they
1.312 - * must be re-acquired under lock anyway to ensure sequential
1.313 - * consistency of updates (and in any case may be undetectably
1.314 - * stale), but they will normally be much faster to re-locate.
1.315 - * Also, scanAndLockForPut speculatively creates a fresh node
1.316 - * to use in put if no node is found.
1.317 - */
1.318 -
1.319 - private static final long serialVersionUID = 2249069246763182397L;
1.320 -
1.321 - /**
1.322 - * The maximum number of times to tryLock in a prescan before
1.323 - * possibly blocking on acquire in preparation for a locked
1.324 - * segment operation. On multiprocessors, using a bounded
1.325 - * number of retries maintains cache acquired while locating
1.326 - * nodes.
1.327 - */
1.328 - static final int MAX_SCAN_RETRIES =
1.329 - Runtime.getRuntime().availableProcessors() > 1 ? 64 : 1;
1.330 -
1.331 - /**
1.332 - * The per-segment table. Elements are accessed via
1.333 - * entryAt/setEntryAt providing volatile semantics.
1.334 - */
1.335 - transient volatile HashEntry<K,V>[] table;
1.336 -
1.337 - /**
1.338 - * The number of elements. Accessed only either within locks
1.339 - * or among other volatile reads that maintain visibility.
1.340 - */
1.341 - transient int count;
1.342 -
1.343 - /**
1.344 - * The total number of mutative operations in this segment.
1.345 - * Even though this may overflows 32 bits, it provides
1.346 - * sufficient accuracy for stability checks in CHM isEmpty()
1.347 - * and size() methods. Accessed only either within locks or
1.348 - * among other volatile reads that maintain visibility.
1.349 - */
1.350 - transient int modCount;
1.351 -
1.352 - /**
1.353 - * The table is rehashed when its size exceeds this threshold.
1.354 - * (The value of this field is always <tt>(int)(capacity *
1.355 - * loadFactor)</tt>.)
1.356 - */
1.357 - transient int threshold;
1.358 -
1.359 - /**
1.360 - * The load factor for the hash table. Even though this value
1.361 - * is same for all segments, it is replicated to avoid needing
1.362 - * links to outer object.
1.363 - * @serial
1.364 - */
1.365 - final float loadFactor;
1.366 -
1.367 - Segment(float lf, int threshold, HashEntry<K,V>[] tab) {
1.368 - this.loadFactor = lf;
1.369 - this.threshold = threshold;
1.370 - this.table = tab;
1.371 - }
1.372 -
1.373 - final V put(K key, int hash, V value, boolean onlyIfAbsent) {
1.374 - HashEntry<K,V> node = tryLock() ? null :
1.375 - scanAndLockForPut(key, hash, value);
1.376 - V oldValue;
1.377 - try {
1.378 - HashEntry<K,V>[] tab = table;
1.379 - int index = (tab.length - 1) & hash;
1.380 - HashEntry<K,V> first = entryAt(tab, index);
1.381 - for (HashEntry<K,V> e = first;;) {
1.382 - if (e != null) {
1.383 - K k;
1.384 - if ((k = e.key) == key ||
1.385 - (e.hash == hash && key.equals(k))) {
1.386 - oldValue = e.value;
1.387 - if (!onlyIfAbsent) {
1.388 - e.value = value;
1.389 - ++modCount;
1.390 - }
1.391 - break;
1.392 - }
1.393 - e = e.next;
1.394 - }
1.395 - else {
1.396 - if (node != null)
1.397 - node.setNext(first);
1.398 - else
1.399 - node = new HashEntry<K,V>(hash, key, value, first);
1.400 - int c = count + 1;
1.401 - if (c > threshold && tab.length < MAXIMUM_CAPACITY)
1.402 - rehash(node);
1.403 - else
1.404 - setEntryAt(tab, index, node);
1.405 - ++modCount;
1.406 - count = c;
1.407 - oldValue = null;
1.408 - break;
1.409 - }
1.410 - }
1.411 - } finally {
1.412 - unlock();
1.413 - }
1.414 - return oldValue;
1.415 - }
1.416 -
1.417 - /**
1.418 - * Doubles size of table and repacks entries, also adding the
1.419 - * given node to new table
1.420 - */
1.421 - @SuppressWarnings("unchecked")
1.422 - private void rehash(HashEntry<K,V> node) {
1.423 - /*
1.424 - * Reclassify nodes in each list to new table. Because we
1.425 - * are using power-of-two expansion, the elements from
1.426 - * each bin must either stay at same index, or move with a
1.427 - * power of two offset. We eliminate unnecessary node
1.428 - * creation by catching cases where old nodes can be
1.429 - * reused because their next fields won't change.
1.430 - * Statistically, at the default threshold, only about
1.431 - * one-sixth of them need cloning when a table
1.432 - * doubles. The nodes they replace will be garbage
1.433 - * collectable as soon as they are no longer referenced by
1.434 - * any reader thread that may be in the midst of
1.435 - * concurrently traversing table. Entry accesses use plain
1.436 - * array indexing because they are followed by volatile
1.437 - * table write.
1.438 - */
1.439 - HashEntry<K,V>[] oldTable = table;
1.440 - int oldCapacity = oldTable.length;
1.441 - int newCapacity = oldCapacity << 1;
1.442 - threshold = (int)(newCapacity * loadFactor);
1.443 - HashEntry<K,V>[] newTable =
1.444 - (HashEntry<K,V>[]) new HashEntry[newCapacity];
1.445 - int sizeMask = newCapacity - 1;
1.446 - for (int i = 0; i < oldCapacity ; i++) {
1.447 - HashEntry<K,V> e = oldTable[i];
1.448 - if (e != null) {
1.449 - HashEntry<K,V> next = e.next;
1.450 - int idx = e.hash & sizeMask;
1.451 - if (next == null) // Single node on list
1.452 - newTable[idx] = e;
1.453 - else { // Reuse consecutive sequence at same slot
1.454 - HashEntry<K,V> lastRun = e;
1.455 - int lastIdx = idx;
1.456 - for (HashEntry<K,V> last = next;
1.457 - last != null;
1.458 - last = last.next) {
1.459 - int k = last.hash & sizeMask;
1.460 - if (k != lastIdx) {
1.461 - lastIdx = k;
1.462 - lastRun = last;
1.463 - }
1.464 - }
1.465 - newTable[lastIdx] = lastRun;
1.466 - // Clone remaining nodes
1.467 - for (HashEntry<K,V> p = e; p != lastRun; p = p.next) {
1.468 - V v = p.value;
1.469 - int h = p.hash;
1.470 - int k = h & sizeMask;
1.471 - HashEntry<K,V> n = newTable[k];
1.472 - newTable[k] = new HashEntry<K,V>(h, p.key, v, n);
1.473 - }
1.474 - }
1.475 - }
1.476 - }
1.477 - int nodeIndex = node.hash & sizeMask; // add the new node
1.478 - node.setNext(newTable[nodeIndex]);
1.479 - newTable[nodeIndex] = node;
1.480 - table = newTable;
1.481 - }
1.482 -
1.483 - /**
1.484 - * Scans for a node containing given key while trying to
1.485 - * acquire lock, creating and returning one if not found. Upon
1.486 - * return, guarantees that lock is held. UNlike in most
1.487 - * methods, calls to method equals are not screened: Since
1.488 - * traversal speed doesn't matter, we might as well help warm
1.489 - * up the associated code and accesses as well.
1.490 - *
1.491 - * @return a new node if key not found, else null
1.492 - */
1.493 - private HashEntry<K,V> scanAndLockForPut(K key, int hash, V value) {
1.494 - HashEntry<K,V> first = entryForHash(this, hash);
1.495 - HashEntry<K,V> e = first;
1.496 - HashEntry<K,V> node = null;
1.497 - int retries = -1; // negative while locating node
1.498 - while (!tryLock()) {
1.499 - HashEntry<K,V> f; // to recheck first below
1.500 - if (retries < 0) {
1.501 - if (e == null) {
1.502 - if (node == null) // speculatively create node
1.503 - node = new HashEntry<K,V>(hash, key, value, null);
1.504 - retries = 0;
1.505 - }
1.506 - else if (key.equals(e.key))
1.507 - retries = 0;
1.508 - else
1.509 - e = e.next;
1.510 - }
1.511 - else if (++retries > MAX_SCAN_RETRIES) {
1.512 - lock();
1.513 - break;
1.514 - }
1.515 - else if ((retries & 1) == 0 &&
1.516 - (f = entryForHash(this, hash)) != first) {
1.517 - e = first = f; // re-traverse if entry changed
1.518 - retries = -1;
1.519 - }
1.520 - }
1.521 - return node;
1.522 - }
1.523 -
1.524 - /**
1.525 - * Scans for a node containing the given key while trying to
1.526 - * acquire lock for a remove or replace operation. Upon
1.527 - * return, guarantees that lock is held. Note that we must
1.528 - * lock even if the key is not found, to ensure sequential
1.529 - * consistency of updates.
1.530 - */
1.531 - private void scanAndLock(Object key, int hash) {
1.532 - // similar to but simpler than scanAndLockForPut
1.533 - HashEntry<K,V> first = entryForHash(this, hash);
1.534 - HashEntry<K,V> e = first;
1.535 - int retries = -1;
1.536 - while (!tryLock()) {
1.537 - HashEntry<K,V> f;
1.538 - if (retries < 0) {
1.539 - if (e == null || key.equals(e.key))
1.540 - retries = 0;
1.541 - else
1.542 - e = e.next;
1.543 - }
1.544 - else if (++retries > MAX_SCAN_RETRIES) {
1.545 - lock();
1.546 - break;
1.547 - }
1.548 - else if ((retries & 1) == 0 &&
1.549 - (f = entryForHash(this, hash)) != first) {
1.550 - e = first = f;
1.551 - retries = -1;
1.552 - }
1.553 - }
1.554 - }
1.555 -
1.556 - /**
1.557 - * Remove; match on key only if value null, else match both.
1.558 - */
1.559 - final V remove(Object key, int hash, Object value) {
1.560 - if (!tryLock())
1.561 - scanAndLock(key, hash);
1.562 - V oldValue = null;
1.563 - try {
1.564 - HashEntry<K,V>[] tab = table;
1.565 - int index = (tab.length - 1) & hash;
1.566 - HashEntry<K,V> e = entryAt(tab, index);
1.567 - HashEntry<K,V> pred = null;
1.568 - while (e != null) {
1.569 - K k;
1.570 - HashEntry<K,V> next = e.next;
1.571 - if ((k = e.key) == key ||
1.572 - (e.hash == hash && key.equals(k))) {
1.573 - V v = e.value;
1.574 - if (value == null || value == v || value.equals(v)) {
1.575 - if (pred == null)
1.576 - setEntryAt(tab, index, next);
1.577 - else
1.578 - pred.setNext(next);
1.579 - ++modCount;
1.580 - --count;
1.581 - oldValue = v;
1.582 - }
1.583 - break;
1.584 - }
1.585 - pred = e;
1.586 - e = next;
1.587 - }
1.588 - } finally {
1.589 - unlock();
1.590 - }
1.591 - return oldValue;
1.592 - }
1.593 -
1.594 - final boolean replace(K key, int hash, V oldValue, V newValue) {
1.595 - if (!tryLock())
1.596 - scanAndLock(key, hash);
1.597 - boolean replaced = false;
1.598 - try {
1.599 - HashEntry<K,V> e;
1.600 - for (e = entryForHash(this, hash); e != null; e = e.next) {
1.601 - K k;
1.602 - if ((k = e.key) == key ||
1.603 - (e.hash == hash && key.equals(k))) {
1.604 - if (oldValue.equals(e.value)) {
1.605 - e.value = newValue;
1.606 - ++modCount;
1.607 - replaced = true;
1.608 - }
1.609 - break;
1.610 - }
1.611 - }
1.612 - } finally {
1.613 - unlock();
1.614 - }
1.615 - return replaced;
1.616 - }
1.617 -
1.618 - final V replace(K key, int hash, V value) {
1.619 - if (!tryLock())
1.620 - scanAndLock(key, hash);
1.621 - V oldValue = null;
1.622 - try {
1.623 - HashEntry<K,V> e;
1.624 - for (e = entryForHash(this, hash); e != null; e = e.next) {
1.625 - K k;
1.626 - if ((k = e.key) == key ||
1.627 - (e.hash == hash && key.equals(k))) {
1.628 - oldValue = e.value;
1.629 - e.value = value;
1.630 - ++modCount;
1.631 - break;
1.632 - }
1.633 - }
1.634 - } finally {
1.635 - unlock();
1.636 - }
1.637 - return oldValue;
1.638 - }
1.639 -
1.640 - final void clear() {
1.641 - lock();
1.642 - try {
1.643 - HashEntry<K,V>[] tab = table;
1.644 - for (int i = 0; i < tab.length ; i++)
1.645 - setEntryAt(tab, i, null);
1.646 - ++modCount;
1.647 - count = 0;
1.648 - } finally {
1.649 - unlock();
1.650 - }
1.651 - }
1.652 - }
1.653 -
1.654 - // Accessing segments
1.655 -
1.656 - /**
1.657 - * Gets the jth element of given segment array (if nonnull) with
1.658 - * volatile element access semantics via Unsafe. (The null check
1.659 - * can trigger harmlessly only during deserialization.) Note:
1.660 - * because each element of segments array is set only once (using
1.661 - * fully ordered writes), some performance-sensitive methods rely
1.662 - * on this method only as a recheck upon null reads.
1.663 - */
1.664 - @SuppressWarnings("unchecked")
1.665 - static final <K,V> Segment<K,V> segmentAt(Segment<K,V>[] ss, int j) {
1.666 - long u = (j << SSHIFT) + SBASE;
1.667 - return ss == null ? null :
1.668 - (Segment<K,V>) UNSAFE.getObjectVolatile(ss, u);
1.669 - }
1.670 -
1.671 - /**
1.672 - * Returns the segment for the given index, creating it and
1.673 - * recording in segment table (via CAS) if not already present.
1.674 - *
1.675 - * @param k the index
1.676 - * @return the segment
1.677 - */
1.678 - @SuppressWarnings("unchecked")
1.679 - private Segment<K,V> ensureSegment(int k) {
1.680 - final Segment<K,V>[] ss = this.segments;
1.681 - long u = (k << SSHIFT) + SBASE; // raw offset
1.682 - Segment<K,V> seg;
1.683 - if ((seg = (Segment<K,V>)UNSAFE.getObjectVolatile(ss, u)) == null) {
1.684 - Segment<K,V> proto = ss[0]; // use segment 0 as prototype
1.685 - int cap = proto.table.length;
1.686 - float lf = proto.loadFactor;
1.687 - int threshold = (int)(cap * lf);
1.688 - HashEntry<K,V>[] tab = (HashEntry<K,V>[])new HashEntry[cap];
1.689 - if ((seg = (Segment<K,V>)UNSAFE.getObjectVolatile(ss, u))
1.690 - == null) { // recheck
1.691 - Segment<K,V> s = new Segment<K,V>(lf, threshold, tab);
1.692 - while ((seg = (Segment<K,V>)UNSAFE.getObjectVolatile(ss, u))
1.693 - == null) {
1.694 - if (UNSAFE.compareAndSwapObject(ss, u, null, seg = s))
1.695 - break;
1.696 - }
1.697 - }
1.698 - }
1.699 - return seg;
1.700 - }
1.701 -
1.702 - // Hash-based segment and entry accesses
1.703 -
1.704 - /**
1.705 - * Get the segment for the given hash
1.706 - */
1.707 - @SuppressWarnings("unchecked")
1.708 - private Segment<K,V> segmentForHash(int h) {
1.709 - long u = (((h >>> segmentShift) & segmentMask) << SSHIFT) + SBASE;
1.710 - return (Segment<K,V>) UNSAFE.getObjectVolatile(segments, u);
1.711 - }
1.712 -
1.713 - /**
1.714 - * Gets the table entry for the given segment and hash
1.715 - */
1.716 - @SuppressWarnings("unchecked")
1.717 - static final <K,V> HashEntry<K,V> entryForHash(Segment<K,V> seg, int h) {
1.718 - HashEntry<K,V>[] tab;
1.719 - return (seg == null || (tab = seg.table) == null) ? null :
1.720 - (HashEntry<K,V>) UNSAFE.getObjectVolatile
1.721 - (tab, ((long)(((tab.length - 1) & h)) << TSHIFT) + TBASE);
1.722 - }
1.723 -
1.724 - /* ---------------- Public operations -------------- */
1.725
1.726 /**
1.727 * Creates a new, empty map with the specified initial
1.728 @@ -736,32 +146,7 @@
1.729 float loadFactor, int concurrencyLevel) {
1.730 if (!(loadFactor > 0) || initialCapacity < 0 || concurrencyLevel <= 0)
1.731 throw new IllegalArgumentException();
1.732 - if (concurrencyLevel > MAX_SEGMENTS)
1.733 - concurrencyLevel = MAX_SEGMENTS;
1.734 - // Find power-of-two sizes best matching arguments
1.735 - int sshift = 0;
1.736 - int ssize = 1;
1.737 - while (ssize < concurrencyLevel) {
1.738 - ++sshift;
1.739 - ssize <<= 1;
1.740 - }
1.741 - this.segmentShift = 32 - sshift;
1.742 - this.segmentMask = ssize - 1;
1.743 - if (initialCapacity > MAXIMUM_CAPACITY)
1.744 - initialCapacity = MAXIMUM_CAPACITY;
1.745 - int c = initialCapacity / ssize;
1.746 - if (c * ssize < initialCapacity)
1.747 - ++c;
1.748 - int cap = MIN_SEGMENT_TABLE_CAPACITY;
1.749 - while (cap < c)
1.750 - cap <<= 1;
1.751 - // create segments and segments[0]
1.752 - Segment<K,V> s0 =
1.753 - new Segment<K,V>(loadFactor, (int)(cap * loadFactor),
1.754 - (HashEntry<K,V>[])new HashEntry[cap]);
1.755 - Segment<K,V>[] ss = (Segment<K,V>[])new Segment[ssize];
1.756 - UNSAFE.putOrderedObject(ss, SBASE, s0); // ordered write of segments[0]
1.757 - this.segments = ss;
1.758 + delegate = new HashMap<>(initialCapacity, loadFactor);
1.759 }
1.760
1.761 /**
1.762 @@ -817,706 +202,126 @@
1.763 DEFAULT_LOAD_FACTOR, DEFAULT_CONCURRENCY_LEVEL);
1.764 putAll(m);
1.765 }
1.766 +
1.767
1.768 - /**
1.769 - * Returns <tt>true</tt> if this map contains no key-value mappings.
1.770 - *
1.771 - * @return <tt>true</tt> if this map contains no key-value mappings
1.772 - */
1.773 - public boolean isEmpty() {
1.774 - /*
1.775 - * Sum per-segment modCounts to avoid mis-reporting when
1.776 - * elements are concurrently added and removed in one segment
1.777 - * while checking another, in which case the table was never
1.778 - * actually empty at any point. (The sum ensures accuracy up
1.779 - * through at least 1<<31 per-segment modifications before
1.780 - * recheck.) Methods size() and containsValue() use similar
1.781 - * constructions for stability checks.
1.782 - */
1.783 - long sum = 0L;
1.784 - final Segment<K,V>[] segments = this.segments;
1.785 - for (int j = 0; j < segments.length; ++j) {
1.786 - Segment<K,V> seg = segmentAt(segments, j);
1.787 - if (seg != null) {
1.788 - if (seg.count != 0)
1.789 - return false;
1.790 - sum += seg.modCount;
1.791 - }
1.792 - }
1.793 - if (sum != 0L) { // recheck unless no modifications
1.794 - for (int j = 0; j < segments.length; ++j) {
1.795 - Segment<K,V> seg = segmentAt(segments, j);
1.796 - if (seg != null) {
1.797 - if (seg.count != 0)
1.798 - return false;
1.799 - sum -= seg.modCount;
1.800 - }
1.801 - }
1.802 - if (sum != 0L)
1.803 - return false;
1.804 - }
1.805 - return true;
1.806 + @Override
1.807 + public int size() {
1.808 + return delegate.size();
1.809 }
1.810
1.811 - /**
1.812 - * Returns the number of key-value mappings in this map. If the
1.813 - * map contains more than <tt>Integer.MAX_VALUE</tt> elements, returns
1.814 - * <tt>Integer.MAX_VALUE</tt>.
1.815 - *
1.816 - * @return the number of key-value mappings in this map
1.817 - */
1.818 - public int size() {
1.819 - // Try a few times to get accurate count. On failure due to
1.820 - // continuous async changes in table, resort to locking.
1.821 - final Segment<K,V>[] segments = this.segments;
1.822 - int size;
1.823 - boolean overflow; // true if size overflows 32 bits
1.824 - long sum; // sum of modCounts
1.825 - long last = 0L; // previous sum
1.826 - int retries = -1; // first iteration isn't retry
1.827 - try {
1.828 - for (;;) {
1.829 - if (retries++ == RETRIES_BEFORE_LOCK) {
1.830 - for (int j = 0; j < segments.length; ++j)
1.831 - ensureSegment(j).lock(); // force creation
1.832 - }
1.833 - sum = 0L;
1.834 - size = 0;
1.835 - overflow = false;
1.836 - for (int j = 0; j < segments.length; ++j) {
1.837 - Segment<K,V> seg = segmentAt(segments, j);
1.838 - if (seg != null) {
1.839 - sum += seg.modCount;
1.840 - int c = seg.count;
1.841 - if (c < 0 || (size += c) < 0)
1.842 - overflow = true;
1.843 - }
1.844 - }
1.845 - if (sum == last)
1.846 - break;
1.847 - last = sum;
1.848 - }
1.849 - } finally {
1.850 - if (retries > RETRIES_BEFORE_LOCK) {
1.851 - for (int j = 0; j < segments.length; ++j)
1.852 - segmentAt(segments, j).unlock();
1.853 - }
1.854 - }
1.855 - return overflow ? Integer.MAX_VALUE : size;
1.856 + @Override
1.857 + public boolean isEmpty() {
1.858 + return delegate.isEmpty();
1.859 }
1.860
1.861 - /**
1.862 - * Returns the value to which the specified key is mapped,
1.863 - * or {@code null} if this map contains no mapping for the key.
1.864 - *
1.865 - * <p>More formally, if this map contains a mapping from a key
1.866 - * {@code k} to a value {@code v} such that {@code key.equals(k)},
1.867 - * then this method returns {@code v}; otherwise it returns
1.868 - * {@code null}. (There can be at most one such mapping.)
1.869 - *
1.870 - * @throws NullPointerException if the specified key is null
1.871 - */
1.872 - public V get(Object key) {
1.873 - Segment<K,V> s; // manually integrate access methods to reduce overhead
1.874 - HashEntry<K,V>[] tab;
1.875 - int h = hash(key.hashCode());
1.876 - long u = (((h >>> segmentShift) & segmentMask) << SSHIFT) + SBASE;
1.877 - if ((s = (Segment<K,V>)UNSAFE.getObjectVolatile(segments, u)) != null &&
1.878 - (tab = s.table) != null) {
1.879 - for (HashEntry<K,V> e = (HashEntry<K,V>) UNSAFE.getObjectVolatile
1.880 - (tab, ((long)(((tab.length - 1) & h)) << TSHIFT) + TBASE);
1.881 - e != null; e = e.next) {
1.882 - K k;
1.883 - if ((k = e.key) == key || (e.hash == h && key.equals(k)))
1.884 - return e.value;
1.885 - }
1.886 - }
1.887 - return null;
1.888 + @Override
1.889 + public boolean containsKey(Object key) {
1.890 + return delegate.containsKey(key);
1.891 }
1.892
1.893 - /**
1.894 - * Tests if the specified object is a key in this table.
1.895 - *
1.896 - * @param key possible key
1.897 - * @return <tt>true</tt> if and only if the specified object
1.898 - * is a key in this table, as determined by the
1.899 - * <tt>equals</tt> method; <tt>false</tt> otherwise.
1.900 - * @throws NullPointerException if the specified key is null
1.901 - */
1.902 - @SuppressWarnings("unchecked")
1.903 - public boolean containsKey(Object key) {
1.904 - Segment<K,V> s; // same as get() except no need for volatile value read
1.905 - HashEntry<K,V>[] tab;
1.906 - int h = hash(key.hashCode());
1.907 - long u = (((h >>> segmentShift) & segmentMask) << SSHIFT) + SBASE;
1.908 - if ((s = (Segment<K,V>)UNSAFE.getObjectVolatile(segments, u)) != null &&
1.909 - (tab = s.table) != null) {
1.910 - for (HashEntry<K,V> e = (HashEntry<K,V>) UNSAFE.getObjectVolatile
1.911 - (tab, ((long)(((tab.length - 1) & h)) << TSHIFT) + TBASE);
1.912 - e != null; e = e.next) {
1.913 - K k;
1.914 - if ((k = e.key) == key || (e.hash == h && key.equals(k)))
1.915 - return true;
1.916 - }
1.917 - }
1.918 - return false;
1.919 + @Override
1.920 + public boolean containsValue(Object value) {
1.921 + return delegate.containsValue(value);
1.922 }
1.923
1.924 - /**
1.925 - * Returns <tt>true</tt> if this map maps one or more keys to the
1.926 - * specified value. Note: This method requires a full internal
1.927 - * traversal of the hash table, and so is much slower than
1.928 - * method <tt>containsKey</tt>.
1.929 - *
1.930 - * @param value value whose presence in this map is to be tested
1.931 - * @return <tt>true</tt> if this map maps one or more keys to the
1.932 - * specified value
1.933 - * @throws NullPointerException if the specified value is null
1.934 - */
1.935 - public boolean containsValue(Object value) {
1.936 - // Same idea as size()
1.937 - if (value == null)
1.938 - throw new NullPointerException();
1.939 - final Segment<K,V>[] segments = this.segments;
1.940 - boolean found = false;
1.941 - long last = 0;
1.942 - int retries = -1;
1.943 - try {
1.944 - outer: for (;;) {
1.945 - if (retries++ == RETRIES_BEFORE_LOCK) {
1.946 - for (int j = 0; j < segments.length; ++j)
1.947 - ensureSegment(j).lock(); // force creation
1.948 - }
1.949 - long hashSum = 0L;
1.950 - int sum = 0;
1.951 - for (int j = 0; j < segments.length; ++j) {
1.952 - HashEntry<K,V>[] tab;
1.953 - Segment<K,V> seg = segmentAt(segments, j);
1.954 - if (seg != null && (tab = seg.table) != null) {
1.955 - for (int i = 0 ; i < tab.length; i++) {
1.956 - HashEntry<K,V> e;
1.957 - for (e = entryAt(tab, i); e != null; e = e.next) {
1.958 - V v = e.value;
1.959 - if (v != null && value.equals(v)) {
1.960 - found = true;
1.961 - break outer;
1.962 - }
1.963 - }
1.964 - }
1.965 - sum += seg.modCount;
1.966 - }
1.967 - }
1.968 - if (retries > 0 && sum == last)
1.969 - break;
1.970 - last = sum;
1.971 - }
1.972 - } finally {
1.973 - if (retries > RETRIES_BEFORE_LOCK) {
1.974 - for (int j = 0; j < segments.length; ++j)
1.975 - segmentAt(segments, j).unlock();
1.976 - }
1.977 - }
1.978 - return found;
1.979 + @Override
1.980 + public V get(Object key) {
1.981 + return delegate.get(key);
1.982 }
1.983
1.984 - /**
1.985 - * Legacy method testing if some key maps into the specified value
1.986 - * in this table. This method is identical in functionality to
1.987 - * {@link #containsValue}, and exists solely to ensure
1.988 - * full compatibility with class {@link java.util.Hashtable},
1.989 - * which supported this method prior to introduction of the
1.990 - * Java Collections framework.
1.991 -
1.992 - * @param value a value to search for
1.993 - * @return <tt>true</tt> if and only if some key maps to the
1.994 - * <tt>value</tt> argument in this table as
1.995 - * determined by the <tt>equals</tt> method;
1.996 - * <tt>false</tt> otherwise
1.997 - * @throws NullPointerException if the specified value is null
1.998 - */
1.999 - public boolean contains(Object value) {
1.1000 - return containsValue(value);
1.1001 + @Override
1.1002 + public V put(K key, V value) {
1.1003 + return delegate.put(key, value);
1.1004 }
1.1005
1.1006 - /**
1.1007 - * Maps the specified key to the specified value in this table.
1.1008 - * Neither the key nor the value can be null.
1.1009 - *
1.1010 - * <p> The value can be retrieved by calling the <tt>get</tt> method
1.1011 - * with a key that is equal to the original key.
1.1012 - *
1.1013 - * @param key key with which the specified value is to be associated
1.1014 - * @param value value to be associated with the specified key
1.1015 - * @return the previous value associated with <tt>key</tt>, or
1.1016 - * <tt>null</tt> if there was no mapping for <tt>key</tt>
1.1017 - * @throws NullPointerException if the specified key or value is null
1.1018 - */
1.1019 - @SuppressWarnings("unchecked")
1.1020 - public V put(K key, V value) {
1.1021 - Segment<K,V> s;
1.1022 - if (value == null)
1.1023 - throw new NullPointerException();
1.1024 - int hash = hash(key.hashCode());
1.1025 - int j = (hash >>> segmentShift) & segmentMask;
1.1026 - if ((s = (Segment<K,V>)UNSAFE.getObject // nonvolatile; recheck
1.1027 - (segments, (j << SSHIFT) + SBASE)) == null) // in ensureSegment
1.1028 - s = ensureSegment(j);
1.1029 - return s.put(key, hash, value, false);
1.1030 + @Override
1.1031 + public V remove(Object key) {
1.1032 + return delegate.remove(key);
1.1033 }
1.1034
1.1035 - /**
1.1036 - * {@inheritDoc}
1.1037 - *
1.1038 - * @return the previous value associated with the specified key,
1.1039 - * or <tt>null</tt> if there was no mapping for the key
1.1040 - * @throws NullPointerException if the specified key or value is null
1.1041 - */
1.1042 - @SuppressWarnings("unchecked")
1.1043 - public V putIfAbsent(K key, V value) {
1.1044 - Segment<K,V> s;
1.1045 - if (value == null)
1.1046 - throw new NullPointerException();
1.1047 - int hash = hash(key.hashCode());
1.1048 - int j = (hash >>> segmentShift) & segmentMask;
1.1049 - if ((s = (Segment<K,V>)UNSAFE.getObject
1.1050 - (segments, (j << SSHIFT) + SBASE)) == null)
1.1051 - s = ensureSegment(j);
1.1052 - return s.put(key, hash, value, true);
1.1053 + @Override
1.1054 + public void putAll(Map<? extends K, ? extends V> m) {
1.1055 + delegate.putAll(m);
1.1056 }
1.1057
1.1058 - /**
1.1059 - * Copies all of the mappings from the specified map to this one.
1.1060 - * These mappings replace any mappings that this map had for any of the
1.1061 - * keys currently in the specified map.
1.1062 - *
1.1063 - * @param m mappings to be stored in this map
1.1064 - */
1.1065 - public void putAll(Map<? extends K, ? extends V> m) {
1.1066 - for (Map.Entry<? extends K, ? extends V> e : m.entrySet())
1.1067 - put(e.getKey(), e.getValue());
1.1068 + @Override
1.1069 + public void clear() {
1.1070 + delegate.clear();
1.1071 }
1.1072
1.1073 - /**
1.1074 - * Removes the key (and its corresponding value) from this map.
1.1075 - * This method does nothing if the key is not in the map.
1.1076 - *
1.1077 - * @param key the key that needs to be removed
1.1078 - * @return the previous value associated with <tt>key</tt>, or
1.1079 - * <tt>null</tt> if there was no mapping for <tt>key</tt>
1.1080 - * @throws NullPointerException if the specified key is null
1.1081 - */
1.1082 - public V remove(Object key) {
1.1083 - int hash = hash(key.hashCode());
1.1084 - Segment<K,V> s = segmentForHash(hash);
1.1085 - return s == null ? null : s.remove(key, hash, null);
1.1086 + @Override
1.1087 + public Set<K> keySet() {
1.1088 + return delegate.keySet();
1.1089 }
1.1090
1.1091 - /**
1.1092 - * {@inheritDoc}
1.1093 - *
1.1094 - * @throws NullPointerException if the specified key is null
1.1095 - */
1.1096 - public boolean remove(Object key, Object value) {
1.1097 - int hash = hash(key.hashCode());
1.1098 - Segment<K,V> s;
1.1099 - return value != null && (s = segmentForHash(hash)) != null &&
1.1100 - s.remove(key, hash, value) != null;
1.1101 + @Override
1.1102 + public Collection<V> values() {
1.1103 + return delegate.values();
1.1104 }
1.1105
1.1106 - /**
1.1107 - * {@inheritDoc}
1.1108 - *
1.1109 - * @throws NullPointerException if any of the arguments are null
1.1110 - */
1.1111 - public boolean replace(K key, V oldValue, V newValue) {
1.1112 - int hash = hash(key.hashCode());
1.1113 - if (oldValue == null || newValue == null)
1.1114 - throw new NullPointerException();
1.1115 - Segment<K,V> s = segmentForHash(hash);
1.1116 - return s != null && s.replace(key, hash, oldValue, newValue);
1.1117 + @Override
1.1118 + public Set<Entry<K, V>> entrySet() {
1.1119 + return delegate.entrySet();
1.1120 }
1.1121
1.1122 - /**
1.1123 - * {@inheritDoc}
1.1124 - *
1.1125 - * @return the previous value associated with the specified key,
1.1126 - * or <tt>null</tt> if there was no mapping for the key
1.1127 - * @throws NullPointerException if the specified key or value is null
1.1128 - */
1.1129 - public V replace(K key, V value) {
1.1130 - int hash = hash(key.hashCode());
1.1131 - if (value == null)
1.1132 - throw new NullPointerException();
1.1133 - Segment<K,V> s = segmentForHash(hash);
1.1134 - return s == null ? null : s.replace(key, hash, value);
1.1135 + @Override
1.1136 + public boolean equals(Object o) {
1.1137 + return delegate.equals(o);
1.1138 }
1.1139
1.1140 - /**
1.1141 - * Removes all of the mappings from this map.
1.1142 - */
1.1143 - public void clear() {
1.1144 - final Segment<K,V>[] segments = this.segments;
1.1145 - for (int j = 0; j < segments.length; ++j) {
1.1146 - Segment<K,V> s = segmentAt(segments, j);
1.1147 - if (s != null)
1.1148 - s.clear();
1.1149 + @Override
1.1150 + public int hashCode() {
1.1151 + return delegate.hashCode();
1.1152 + }
1.1153 +
1.1154 + @Override
1.1155 + public String toString() {
1.1156 + return delegate.toString();
1.1157 + }
1.1158 +
1.1159 + @Override
1.1160 + public V putIfAbsent(K key, V value) {
1.1161 + V old = delegate.get(key);
1.1162 + if (old == null) {
1.1163 + return delegate.put(key, value);
1.1164 + }
1.1165 + return old;
1.1166 + }
1.1167 +
1.1168 + @Override
1.1169 + public boolean remove(Object key, Object value) {
1.1170 + if (equals(value, delegate.get(key))) {
1.1171 + delegate.remove(key);
1.1172 + return true;
1.1173 + } else {
1.1174 + return false;
1.1175 }
1.1176 }
1.1177
1.1178 - /**
1.1179 - * Returns a {@link Set} view of the keys contained in this map.
1.1180 - * The set is backed by the map, so changes to the map are
1.1181 - * reflected in the set, and vice-versa. The set supports element
1.1182 - * removal, which removes the corresponding mapping from this map,
1.1183 - * via the <tt>Iterator.remove</tt>, <tt>Set.remove</tt>,
1.1184 - * <tt>removeAll</tt>, <tt>retainAll</tt>, and <tt>clear</tt>
1.1185 - * operations. It does not support the <tt>add</tt> or
1.1186 - * <tt>addAll</tt> operations.
1.1187 - *
1.1188 - * <p>The view's <tt>iterator</tt> is a "weakly consistent" iterator
1.1189 - * that will never throw {@link ConcurrentModificationException},
1.1190 - * and guarantees to traverse elements as they existed upon
1.1191 - * construction of the iterator, and may (but is not guaranteed to)
1.1192 - * reflect any modifications subsequent to construction.
1.1193 - */
1.1194 - public Set<K> keySet() {
1.1195 - Set<K> ks = keySet;
1.1196 - return (ks != null) ? ks : (keySet = new KeySet());
1.1197 - }
1.1198 -
1.1199 - /**
1.1200 - * Returns a {@link Collection} view of the values contained in this map.
1.1201 - * The collection is backed by the map, so changes to the map are
1.1202 - * reflected in the collection, and vice-versa. The collection
1.1203 - * supports element removal, which removes the corresponding
1.1204 - * mapping from this map, via the <tt>Iterator.remove</tt>,
1.1205 - * <tt>Collection.remove</tt>, <tt>removeAll</tt>,
1.1206 - * <tt>retainAll</tt>, and <tt>clear</tt> operations. It does not
1.1207 - * support the <tt>add</tt> or <tt>addAll</tt> operations.
1.1208 - *
1.1209 - * <p>The view's <tt>iterator</tt> is a "weakly consistent" iterator
1.1210 - * that will never throw {@link ConcurrentModificationException},
1.1211 - * and guarantees to traverse elements as they existed upon
1.1212 - * construction of the iterator, and may (but is not guaranteed to)
1.1213 - * reflect any modifications subsequent to construction.
1.1214 - */
1.1215 - public Collection<V> values() {
1.1216 - Collection<V> vs = values;
1.1217 - return (vs != null) ? vs : (values = new Values());
1.1218 - }
1.1219 -
1.1220 - /**
1.1221 - * Returns a {@link Set} view of the mappings contained in this map.
1.1222 - * The set is backed by the map, so changes to the map are
1.1223 - * reflected in the set, and vice-versa. The set supports element
1.1224 - * removal, which removes the corresponding mapping from the map,
1.1225 - * via the <tt>Iterator.remove</tt>, <tt>Set.remove</tt>,
1.1226 - * <tt>removeAll</tt>, <tt>retainAll</tt>, and <tt>clear</tt>
1.1227 - * operations. It does not support the <tt>add</tt> or
1.1228 - * <tt>addAll</tt> operations.
1.1229 - *
1.1230 - * <p>The view's <tt>iterator</tt> is a "weakly consistent" iterator
1.1231 - * that will never throw {@link ConcurrentModificationException},
1.1232 - * and guarantees to traverse elements as they existed upon
1.1233 - * construction of the iterator, and may (but is not guaranteed to)
1.1234 - * reflect any modifications subsequent to construction.
1.1235 - */
1.1236 - public Set<Map.Entry<K,V>> entrySet() {
1.1237 - Set<Map.Entry<K,V>> es = entrySet;
1.1238 - return (es != null) ? es : (entrySet = new EntrySet());
1.1239 - }
1.1240 -
1.1241 - /**
1.1242 - * Returns an enumeration of the keys in this table.
1.1243 - *
1.1244 - * @return an enumeration of the keys in this table
1.1245 - * @see #keySet()
1.1246 - */
1.1247 - public Enumeration<K> keys() {
1.1248 - return new KeyIterator();
1.1249 - }
1.1250 -
1.1251 - /**
1.1252 - * Returns an enumeration of the values in this table.
1.1253 - *
1.1254 - * @return an enumeration of the values in this table
1.1255 - * @see #values()
1.1256 - */
1.1257 - public Enumeration<V> elements() {
1.1258 - return new ValueIterator();
1.1259 - }
1.1260 -
1.1261 - /* ---------------- Iterator Support -------------- */
1.1262 -
1.1263 - abstract class HashIterator {
1.1264 - int nextSegmentIndex;
1.1265 - int nextTableIndex;
1.1266 - HashEntry<K,V>[] currentTable;
1.1267 - HashEntry<K, V> nextEntry;
1.1268 - HashEntry<K, V> lastReturned;
1.1269 -
1.1270 - HashIterator() {
1.1271 - nextSegmentIndex = segments.length - 1;
1.1272 - nextTableIndex = -1;
1.1273 - advance();
1.1274 - }
1.1275 -
1.1276 - /**
1.1277 - * Set nextEntry to first node of next non-empty table
1.1278 - * (in backwards order, to simplify checks).
1.1279 - */
1.1280 - final void advance() {
1.1281 - for (;;) {
1.1282 - if (nextTableIndex >= 0) {
1.1283 - if ((nextEntry = entryAt(currentTable,
1.1284 - nextTableIndex--)) != null)
1.1285 - break;
1.1286 - }
1.1287 - else if (nextSegmentIndex >= 0) {
1.1288 - Segment<K,V> seg = segmentAt(segments, nextSegmentIndex--);
1.1289 - if (seg != null && (currentTable = seg.table) != null)
1.1290 - nextTableIndex = currentTable.length - 1;
1.1291 - }
1.1292 - else
1.1293 - break;
1.1294 - }
1.1295 - }
1.1296 -
1.1297 - final HashEntry<K,V> nextEntry() {
1.1298 - HashEntry<K,V> e = nextEntry;
1.1299 - if (e == null)
1.1300 - throw new NoSuchElementException();
1.1301 - lastReturned = e; // cannot assign until after null check
1.1302 - if ((nextEntry = e.next) == null)
1.1303 - advance();
1.1304 - return e;
1.1305 - }
1.1306 -
1.1307 - public final boolean hasNext() { return nextEntry != null; }
1.1308 - public final boolean hasMoreElements() { return nextEntry != null; }
1.1309 -
1.1310 - public final void remove() {
1.1311 - if (lastReturned == null)
1.1312 - throw new IllegalStateException();
1.1313 - ConcurrentHashMap.this.remove(lastReturned.key);
1.1314 - lastReturned = null;
1.1315 + @Override
1.1316 + public boolean replace(K key, V oldValue, V newValue) {
1.1317 + if (equals(oldValue, delegate.get(key))) {
1.1318 + delegate.put(key, newValue);
1.1319 + return true;
1.1320 + } else {
1.1321 + return false;
1.1322 }
1.1323 }
1.1324
1.1325 - final class KeyIterator
1.1326 - extends HashIterator
1.1327 - implements Iterator<K>, Enumeration<K>
1.1328 - {
1.1329 - public final K next() { return super.nextEntry().key; }
1.1330 - public final K nextElement() { return super.nextEntry().key; }
1.1331 - }
1.1332 -
1.1333 - final class ValueIterator
1.1334 - extends HashIterator
1.1335 - implements Iterator<V>, Enumeration<V>
1.1336 - {
1.1337 - public final V next() { return super.nextEntry().value; }
1.1338 - public final V nextElement() { return super.nextEntry().value; }
1.1339 - }
1.1340 -
1.1341 - /**
1.1342 - * Custom Entry class used by EntryIterator.next(), that relays
1.1343 - * setValue changes to the underlying map.
1.1344 - */
1.1345 - final class WriteThroughEntry
1.1346 - extends AbstractMap.SimpleEntry<K,V>
1.1347 - {
1.1348 - WriteThroughEntry(K k, V v) {
1.1349 - super(k,v);
1.1350 - }
1.1351 -
1.1352 - /**
1.1353 - * Set our entry's value and write through to the map. The
1.1354 - * value to return is somewhat arbitrary here. Since a
1.1355 - * WriteThroughEntry does not necessarily track asynchronous
1.1356 - * changes, the most recent "previous" value could be
1.1357 - * different from what we return (or could even have been
1.1358 - * removed in which case the put will re-establish). We do not
1.1359 - * and cannot guarantee more.
1.1360 - */
1.1361 - public V setValue(V value) {
1.1362 - if (value == null) throw new NullPointerException();
1.1363 - V v = super.setValue(value);
1.1364 - ConcurrentHashMap.this.put(getKey(), value);
1.1365 - return v;
1.1366 + @Override
1.1367 + public V replace(K key, V value) {
1.1368 + if (delegate.containsKey(key)) {
1.1369 + return delegate.put(key, value);
1.1370 + } else {
1.1371 + return null;
1.1372 }
1.1373 }
1.1374 -
1.1375 - final class EntryIterator
1.1376 - extends HashIterator
1.1377 - implements Iterator<Entry<K,V>>
1.1378 - {
1.1379 - public Map.Entry<K,V> next() {
1.1380 - HashEntry<K,V> e = super.nextEntry();
1.1381 - return new WriteThroughEntry(e.key, e.value);
1.1382 +
1.1383 + private static boolean equals(Object a, Object b) {
1.1384 + if (a == null) {
1.1385 + return b == null;
1.1386 + } else {
1.1387 + return a.equals(b);
1.1388 }
1.1389 }
1.1390 -
1.1391 - final class KeySet extends AbstractSet<K> {
1.1392 - public Iterator<K> iterator() {
1.1393 - return new KeyIterator();
1.1394 - }
1.1395 - public int size() {
1.1396 - return ConcurrentHashMap.this.size();
1.1397 - }
1.1398 - public boolean isEmpty() {
1.1399 - return ConcurrentHashMap.this.isEmpty();
1.1400 - }
1.1401 - public boolean contains(Object o) {
1.1402 - return ConcurrentHashMap.this.containsKey(o);
1.1403 - }
1.1404 - public boolean remove(Object o) {
1.1405 - return ConcurrentHashMap.this.remove(o) != null;
1.1406 - }
1.1407 - public void clear() {
1.1408 - ConcurrentHashMap.this.clear();
1.1409 - }
1.1410 - }
1.1411 -
1.1412 - final class Values extends AbstractCollection<V> {
1.1413 - public Iterator<V> iterator() {
1.1414 - return new ValueIterator();
1.1415 - }
1.1416 - public int size() {
1.1417 - return ConcurrentHashMap.this.size();
1.1418 - }
1.1419 - public boolean isEmpty() {
1.1420 - return ConcurrentHashMap.this.isEmpty();
1.1421 - }
1.1422 - public boolean contains(Object o) {
1.1423 - return ConcurrentHashMap.this.containsValue(o);
1.1424 - }
1.1425 - public void clear() {
1.1426 - ConcurrentHashMap.this.clear();
1.1427 - }
1.1428 - }
1.1429 -
1.1430 - final class EntrySet extends AbstractSet<Map.Entry<K,V>> {
1.1431 - public Iterator<Map.Entry<K,V>> iterator() {
1.1432 - return new EntryIterator();
1.1433 - }
1.1434 - public boolean contains(Object o) {
1.1435 - if (!(o instanceof Map.Entry))
1.1436 - return false;
1.1437 - Map.Entry<?,?> e = (Map.Entry<?,?>)o;
1.1438 - V v = ConcurrentHashMap.this.get(e.getKey());
1.1439 - return v != null && v.equals(e.getValue());
1.1440 - }
1.1441 - public boolean remove(Object o) {
1.1442 - if (!(o instanceof Map.Entry))
1.1443 - return false;
1.1444 - Map.Entry<?,?> e = (Map.Entry<?,?>)o;
1.1445 - return ConcurrentHashMap.this.remove(e.getKey(), e.getValue());
1.1446 - }
1.1447 - public int size() {
1.1448 - return ConcurrentHashMap.this.size();
1.1449 - }
1.1450 - public boolean isEmpty() {
1.1451 - return ConcurrentHashMap.this.isEmpty();
1.1452 - }
1.1453 - public void clear() {
1.1454 - ConcurrentHashMap.this.clear();
1.1455 - }
1.1456 - }
1.1457 -
1.1458 - /* ---------------- Serialization Support -------------- */
1.1459 -
1.1460 - /**
1.1461 - * Save the state of the <tt>ConcurrentHashMap</tt> instance to a
1.1462 - * stream (i.e., serialize it).
1.1463 - * @param s the stream
1.1464 - * @serialData
1.1465 - * the key (Object) and value (Object)
1.1466 - * for each key-value mapping, followed by a null pair.
1.1467 - * The key-value mappings are emitted in no particular order.
1.1468 - */
1.1469 - private void writeObject(java.io.ObjectOutputStream s) throws IOException {
1.1470 - // force all segments for serialization compatibility
1.1471 - for (int k = 0; k < segments.length; ++k)
1.1472 - ensureSegment(k);
1.1473 - s.defaultWriteObject();
1.1474 -
1.1475 - final Segment<K,V>[] segments = this.segments;
1.1476 - for (int k = 0; k < segments.length; ++k) {
1.1477 - Segment<K,V> seg = segmentAt(segments, k);
1.1478 - seg.lock();
1.1479 - try {
1.1480 - HashEntry<K,V>[] tab = seg.table;
1.1481 - for (int i = 0; i < tab.length; ++i) {
1.1482 - HashEntry<K,V> e;
1.1483 - for (e = entryAt(tab, i); e != null; e = e.next) {
1.1484 - s.writeObject(e.key);
1.1485 - s.writeObject(e.value);
1.1486 - }
1.1487 - }
1.1488 - } finally {
1.1489 - seg.unlock();
1.1490 - }
1.1491 - }
1.1492 - s.writeObject(null);
1.1493 - s.writeObject(null);
1.1494 - }
1.1495 -
1.1496 - /**
1.1497 - * Reconstitute the <tt>ConcurrentHashMap</tt> instance from a
1.1498 - * stream (i.e., deserialize it).
1.1499 - * @param s the stream
1.1500 - */
1.1501 - @SuppressWarnings("unchecked")
1.1502 - private void readObject(java.io.ObjectInputStream s)
1.1503 - throws IOException, ClassNotFoundException {
1.1504 - s.defaultReadObject();
1.1505 -
1.1506 - // Re-initialize segments to be minimally sized, and let grow.
1.1507 - int cap = MIN_SEGMENT_TABLE_CAPACITY;
1.1508 - final Segment<K,V>[] segments = this.segments;
1.1509 - for (int k = 0; k < segments.length; ++k) {
1.1510 - Segment<K,V> seg = segments[k];
1.1511 - if (seg != null) {
1.1512 - seg.threshold = (int)(cap * seg.loadFactor);
1.1513 - seg.table = (HashEntry<K,V>[]) new HashEntry[cap];
1.1514 - }
1.1515 - }
1.1516 -
1.1517 - // Read the keys and values, and put the mappings in the table
1.1518 - for (;;) {
1.1519 - K key = (K) s.readObject();
1.1520 - V value = (V) s.readObject();
1.1521 - if (key == null)
1.1522 - break;
1.1523 - put(key, value);
1.1524 - }
1.1525 - }
1.1526 -
1.1527 - // Unsafe mechanics
1.1528 - private static final sun.misc.Unsafe UNSAFE;
1.1529 - private static final long SBASE;
1.1530 - private static final int SSHIFT;
1.1531 - private static final long TBASE;
1.1532 - private static final int TSHIFT;
1.1533 -
1.1534 - static {
1.1535 - int ss, ts;
1.1536 - try {
1.1537 - UNSAFE = sun.misc.Unsafe.getUnsafe();
1.1538 - Class tc = HashEntry[].class;
1.1539 - Class sc = Segment[].class;
1.1540 - TBASE = UNSAFE.arrayBaseOffset(tc);
1.1541 - SBASE = UNSAFE.arrayBaseOffset(sc);
1.1542 - ts = UNSAFE.arrayIndexScale(tc);
1.1543 - ss = UNSAFE.arrayIndexScale(sc);
1.1544 - } catch (Exception e) {
1.1545 - throw new Error(e);
1.1546 - }
1.1547 - if ((ss & (ss-1)) != 0 || (ts & (ts-1)) != 0)
1.1548 - throw new Error("data type scale not a power of two");
1.1549 - SSHIFT = 31 - Integer.numberOfLeadingZeros(ss);
1.1550 - TSHIFT = 31 - Integer.numberOfLeadingZeros(ts);
1.1551 - }
1.1552 -
1.1553 }
2.1 --- a/rt/emul/compact/src/main/java/java/util/concurrent/atomic/AtomicBoolean.java Thu Oct 03 17:36:44 2013 +0200
2.2 +++ b/rt/emul/compact/src/main/java/java/util/concurrent/atomic/AtomicBoolean.java Fri Oct 04 10:52:01 2013 +0200
2.3 @@ -34,7 +34,6 @@
2.4 */
2.5
2.6 package java.util.concurrent.atomic;
2.7 -import sun.misc.Unsafe;
2.8
2.9 /**
2.10 * A {@code boolean} value that may be updated atomically. See the
2.11 @@ -49,16 +48,6 @@
2.12 */
2.13 public class AtomicBoolean implements java.io.Serializable {
2.14 private static final long serialVersionUID = 4654671469794556979L;
2.15 - // setup to use Unsafe.compareAndSwapInt for updates
2.16 - private static final Unsafe unsafe = Unsafe.getUnsafe();
2.17 - private static final long valueOffset;
2.18 -
2.19 - static {
2.20 - try {
2.21 - valueOffset = unsafe.objectFieldOffset
2.22 - (AtomicBoolean.class.getDeclaredField("value"));
2.23 - } catch (Exception ex) { throw new Error(ex); }
2.24 - }
2.25
2.26 private volatile int value;
2.27
2.28 @@ -98,7 +87,12 @@
2.29 public final boolean compareAndSet(boolean expect, boolean update) {
2.30 int e = expect ? 1 : 0;
2.31 int u = update ? 1 : 0;
2.32 - return unsafe.compareAndSwapInt(this, valueOffset, e, u);
2.33 + if (this.value == e) {
2.34 + this.value = u;
2.35 + return true;
2.36 + } else {
2.37 + return false;
2.38 + }
2.39 }
2.40
2.41 /**
2.42 @@ -114,9 +108,7 @@
2.43 * @return true if successful.
2.44 */
2.45 public boolean weakCompareAndSet(boolean expect, boolean update) {
2.46 - int e = expect ? 1 : 0;
2.47 - int u = update ? 1 : 0;
2.48 - return unsafe.compareAndSwapInt(this, valueOffset, e, u);
2.49 + return compareAndSet(expect, update);
2.50 }
2.51
2.52 /**
2.53 @@ -135,8 +127,7 @@
2.54 * @since 1.6
2.55 */
2.56 public final void lazySet(boolean newValue) {
2.57 - int v = newValue ? 1 : 0;
2.58 - unsafe.putOrderedInt(this, valueOffset, v);
2.59 + set(newValue);
2.60 }
2.61
2.62 /**
3.1 --- a/rt/emul/compact/src/main/java/java/util/concurrent/atomic/AtomicInteger.java Thu Oct 03 17:36:44 2013 +0200
3.2 +++ b/rt/emul/compact/src/main/java/java/util/concurrent/atomic/AtomicInteger.java Fri Oct 04 10:52:01 2013 +0200
3.3 @@ -34,7 +34,6 @@
3.4 */
3.5
3.6 package java.util.concurrent.atomic;
3.7 -import sun.misc.Unsafe;
3.8
3.9 /**
3.10 * An {@code int} value that may be updated atomically. See the
3.11 @@ -52,17 +51,6 @@
3.12 public class AtomicInteger extends Number implements java.io.Serializable {
3.13 private static final long serialVersionUID = 6214790243416807050L;
3.14
3.15 - // setup to use Unsafe.compareAndSwapInt for updates
3.16 - private static final Unsafe unsafe = Unsafe.getUnsafe();
3.17 - private static final long valueOffset;
3.18 -
3.19 - static {
3.20 - try {
3.21 - valueOffset = unsafe.objectFieldOffset
3.22 - (AtomicInteger.class.getDeclaredField("value"));
3.23 - } catch (Exception ex) { throw new Error(ex); }
3.24 - }
3.25 -
3.26 private volatile int value;
3.27
3.28 /**
3.29 @@ -105,7 +93,7 @@
3.30 * @since 1.6
3.31 */
3.32 public final void lazySet(int newValue) {
3.33 - unsafe.putOrderedInt(this, valueOffset, newValue);
3.34 + value = newValue;
3.35 }
3.36
3.37 /**
3.38 @@ -132,7 +120,12 @@
3.39 * the actual value was not equal to the expected value.
3.40 */
3.41 public final boolean compareAndSet(int expect, int update) {
3.42 - return unsafe.compareAndSwapInt(this, valueOffset, expect, update);
3.43 + if (value == expect) {
3.44 + value = update;
3.45 + return true;
3.46 + } else {
3.47 + return false;
3.48 + }
3.49 }
3.50
3.51 /**
3.52 @@ -148,7 +141,7 @@
3.53 * @return true if successful.
3.54 */
3.55 public final boolean weakCompareAndSet(int expect, int update) {
3.56 - return unsafe.compareAndSwapInt(this, valueOffset, expect, update);
3.57 + return compareAndSet(expect, update);
3.58 }
3.59
3.60 /**
4.1 --- a/rt/emul/compact/src/main/java/java/util/concurrent/atomic/AtomicIntegerArray.java Thu Oct 03 17:36:44 2013 +0200
4.2 +++ b/rt/emul/compact/src/main/java/java/util/concurrent/atomic/AtomicIntegerArray.java Fri Oct 04 10:52:01 2013 +0200
4.3 @@ -34,8 +34,6 @@
4.4 */
4.5
4.6 package java.util.concurrent.atomic;
4.7 -import sun.misc.Unsafe;
4.8 -import java.util.*;
4.9
4.10 /**
4.11 * An {@code int} array in which elements may be updated atomically.
4.12 @@ -48,29 +46,8 @@
4.13 public class AtomicIntegerArray implements java.io.Serializable {
4.14 private static final long serialVersionUID = 2862133569453604235L;
4.15
4.16 - private static final Unsafe unsafe = Unsafe.getUnsafe();
4.17 - private static final int base = unsafe.arrayBaseOffset(int[].class);
4.18 - private static final int shift;
4.19 private final int[] array;
4.20
4.21 - static {
4.22 - int scale = unsafe.arrayIndexScale(int[].class);
4.23 - if ((scale & (scale - 1)) != 0)
4.24 - throw new Error("data type scale not a power of two");
4.25 - shift = 31 - Integer.numberOfLeadingZeros(scale);
4.26 - }
4.27 -
4.28 - private long checkedByteOffset(int i) {
4.29 - if (i < 0 || i >= array.length)
4.30 - throw new IndexOutOfBoundsException("index " + i);
4.31 -
4.32 - return byteOffset(i);
4.33 - }
4.34 -
4.35 - private static long byteOffset(int i) {
4.36 - return ((long) i << shift) + base;
4.37 - }
4.38 -
4.39 /**
4.40 * Creates a new AtomicIntegerArray of the given length, with all
4.41 * elements initially zero.
4.42 @@ -109,11 +86,7 @@
4.43 * @return the current value
4.44 */
4.45 public final int get(int i) {
4.46 - return getRaw(checkedByteOffset(i));
4.47 - }
4.48 -
4.49 - private int getRaw(long offset) {
4.50 - return unsafe.getIntVolatile(array, offset);
4.51 + return array[i];
4.52 }
4.53
4.54 /**
4.55 @@ -123,7 +96,7 @@
4.56 * @param newValue the new value
4.57 */
4.58 public final void set(int i, int newValue) {
4.59 - unsafe.putIntVolatile(array, checkedByteOffset(i), newValue);
4.60 + array[i] = newValue;
4.61 }
4.62
4.63 /**
4.64 @@ -134,7 +107,7 @@
4.65 * @since 1.6
4.66 */
4.67 public final void lazySet(int i, int newValue) {
4.68 - unsafe.putOrderedInt(array, checkedByteOffset(i), newValue);
4.69 + array[i] = newValue;
4.70 }
4.71
4.72 /**
4.73 @@ -146,12 +119,9 @@
4.74 * @return the previous value
4.75 */
4.76 public final int getAndSet(int i, int newValue) {
4.77 - long offset = checkedByteOffset(i);
4.78 - while (true) {
4.79 - int current = getRaw(offset);
4.80 - if (compareAndSetRaw(offset, current, newValue))
4.81 - return current;
4.82 - }
4.83 + int current = array[i];
4.84 + array[i] = newValue;
4.85 + return current;
4.86 }
4.87
4.88 /**
4.89 @@ -165,11 +135,12 @@
4.90 * the actual value was not equal to the expected value.
4.91 */
4.92 public final boolean compareAndSet(int i, int expect, int update) {
4.93 - return compareAndSetRaw(checkedByteOffset(i), expect, update);
4.94 - }
4.95 -
4.96 - private boolean compareAndSetRaw(long offset, int expect, int update) {
4.97 - return unsafe.compareAndSwapInt(array, offset, expect, update);
4.98 + if (array[i] == expect) {
4.99 + array[i] = update;
4.100 + return true;
4.101 + } else {
4.102 + return false;
4.103 + }
4.104 }
4.105
4.106 /**
4.107 @@ -217,12 +188,9 @@
4.108 * @return the previous value
4.109 */
4.110 public final int getAndAdd(int i, int delta) {
4.111 - long offset = checkedByteOffset(i);
4.112 - while (true) {
4.113 - int current = getRaw(offset);
4.114 - if (compareAndSetRaw(offset, current, current + delta))
4.115 - return current;
4.116 - }
4.117 + int v = array[i];
4.118 + array[i] += delta;
4.119 + return v;
4.120 }
4.121
4.122 /**
4.123 @@ -253,13 +221,8 @@
4.124 * @return the updated value
4.125 */
4.126 public final int addAndGet(int i, int delta) {
4.127 - long offset = checkedByteOffset(i);
4.128 - while (true) {
4.129 - int current = getRaw(offset);
4.130 - int next = current + delta;
4.131 - if (compareAndSetRaw(offset, current, next))
4.132 - return next;
4.133 - }
4.134 + array[i] += delta;
4.135 + return array[i];
4.136 }
4.137
4.138 /**
4.139 @@ -274,7 +237,7 @@
4.140 StringBuilder b = new StringBuilder();
4.141 b.append('[');
4.142 for (int i = 0; ; i++) {
4.143 - b.append(getRaw(byteOffset(i)));
4.144 + b.append(get(i));
4.145 if (i == iMax)
4.146 return b.append(']').toString();
4.147 b.append(',').append(' ');
5.1 --- a/rt/emul/compact/src/main/java/java/util/concurrent/atomic/AtomicLong.java Thu Oct 03 17:36:44 2013 +0200
5.2 +++ b/rt/emul/compact/src/main/java/java/util/concurrent/atomic/AtomicLong.java Fri Oct 04 10:52:01 2013 +0200
5.3 @@ -34,7 +34,6 @@
5.4 */
5.5
5.6 package java.util.concurrent.atomic;
5.7 -import sun.misc.Unsafe;
5.8
5.9 /**
5.10 * A {@code long} value that may be updated atomically. See the
5.11 @@ -52,17 +51,6 @@
5.12 public class AtomicLong extends Number implements java.io.Serializable {
5.13 private static final long serialVersionUID = 1927816293512124184L;
5.14
5.15 - // setup to use Unsafe.compareAndSwapLong for updates
5.16 - private static final Unsafe unsafe = Unsafe.getUnsafe();
5.17 - private static final long valueOffset;
5.18 -
5.19 - /**
5.20 - * Records whether the underlying JVM supports lockless
5.21 - * compareAndSwap for longs. While the Unsafe.compareAndSwapLong
5.22 - * method works in either case, some constructions should be
5.23 - * handled at Java level to avoid locking user-visible locks.
5.24 - */
5.25 - static final boolean VM_SUPPORTS_LONG_CAS = VMSupportsCS8();
5.26
5.27 /**
5.28 * Returns whether underlying JVM supports lockless CompareAndSet
5.29 @@ -70,13 +58,6 @@
5.30 */
5.31 private static native boolean VMSupportsCS8();
5.32
5.33 - static {
5.34 - try {
5.35 - valueOffset = unsafe.objectFieldOffset
5.36 - (AtomicLong.class.getDeclaredField("value"));
5.37 - } catch (Exception ex) { throw new Error(ex); }
5.38 - }
5.39 -
5.40 private volatile long value;
5.41
5.42 /**
5.43 @@ -119,7 +100,7 @@
5.44 * @since 1.6
5.45 */
5.46 public final void lazySet(long newValue) {
5.47 - unsafe.putOrderedLong(this, valueOffset, newValue);
5.48 + value = newValue;
5.49 }
5.50
5.51 /**
5.52 @@ -146,7 +127,12 @@
5.53 * the actual value was not equal to the expected value.
5.54 */
5.55 public final boolean compareAndSet(long expect, long update) {
5.56 - return unsafe.compareAndSwapLong(this, valueOffset, expect, update);
5.57 + if (value == expect) {
5.58 + value = update;
5.59 + return true;
5.60 + } else {
5.61 + return false;
5.62 + }
5.63 }
5.64
5.65 /**
5.66 @@ -162,7 +148,7 @@
5.67 * @return true if successful.
5.68 */
5.69 public final boolean weakCompareAndSet(long expect, long update) {
5.70 - return unsafe.compareAndSwapLong(this, valueOffset, expect, update);
5.71 + return compareAndSet(expect, update);
5.72 }
5.73
5.74 /**
6.1 --- a/rt/emul/compact/src/main/java/java/util/concurrent/atomic/AtomicLongArray.java Thu Oct 03 17:36:44 2013 +0200
6.2 +++ b/rt/emul/compact/src/main/java/java/util/concurrent/atomic/AtomicLongArray.java Fri Oct 04 10:52:01 2013 +0200
6.3 @@ -34,8 +34,6 @@
6.4 */
6.5
6.6 package java.util.concurrent.atomic;
6.7 -import sun.misc.Unsafe;
6.8 -import java.util.*;
6.9
6.10 /**
6.11 * A {@code long} array in which elements may be updated atomically.
6.12 @@ -47,29 +45,8 @@
6.13 public class AtomicLongArray implements java.io.Serializable {
6.14 private static final long serialVersionUID = -2308431214976778248L;
6.15
6.16 - private static final Unsafe unsafe = Unsafe.getUnsafe();
6.17 - private static final int base = unsafe.arrayBaseOffset(long[].class);
6.18 - private static final int shift;
6.19 private final long[] array;
6.20
6.21 - static {
6.22 - int scale = unsafe.arrayIndexScale(long[].class);
6.23 - if ((scale & (scale - 1)) != 0)
6.24 - throw new Error("data type scale not a power of two");
6.25 - shift = 31 - Integer.numberOfLeadingZeros(scale);
6.26 - }
6.27 -
6.28 - private long checkedByteOffset(int i) {
6.29 - if (i < 0 || i >= array.length)
6.30 - throw new IndexOutOfBoundsException("index " + i);
6.31 -
6.32 - return byteOffset(i);
6.33 - }
6.34 -
6.35 - private static long byteOffset(int i) {
6.36 - return ((long) i << shift) + base;
6.37 - }
6.38 -
6.39 /**
6.40 * Creates a new AtomicLongArray of the given length, with all
6.41 * elements initially zero.
6.42 @@ -108,11 +85,7 @@
6.43 * @return the current value
6.44 */
6.45 public final long get(int i) {
6.46 - return getRaw(checkedByteOffset(i));
6.47 - }
6.48 -
6.49 - private long getRaw(long offset) {
6.50 - return unsafe.getLongVolatile(array, offset);
6.51 + return array[i];
6.52 }
6.53
6.54 /**
6.55 @@ -122,7 +95,7 @@
6.56 * @param newValue the new value
6.57 */
6.58 public final void set(int i, long newValue) {
6.59 - unsafe.putLongVolatile(array, checkedByteOffset(i), newValue);
6.60 + array[i] = newValue;
6.61 }
6.62
6.63 /**
6.64 @@ -133,7 +106,7 @@
6.65 * @since 1.6
6.66 */
6.67 public final void lazySet(int i, long newValue) {
6.68 - unsafe.putOrderedLong(array, checkedByteOffset(i), newValue);
6.69 + array[i] = newValue;
6.70 }
6.71
6.72
6.73 @@ -146,12 +119,9 @@
6.74 * @return the previous value
6.75 */
6.76 public final long getAndSet(int i, long newValue) {
6.77 - long offset = checkedByteOffset(i);
6.78 - while (true) {
6.79 - long current = getRaw(offset);
6.80 - if (compareAndSetRaw(offset, current, newValue))
6.81 - return current;
6.82 - }
6.83 + long v = array[i];
6.84 + array[i] = newValue;
6.85 + return v;
6.86 }
6.87
6.88 /**
6.89 @@ -165,11 +135,12 @@
6.90 * the actual value was not equal to the expected value.
6.91 */
6.92 public final boolean compareAndSet(int i, long expect, long update) {
6.93 - return compareAndSetRaw(checkedByteOffset(i), expect, update);
6.94 - }
6.95 -
6.96 - private boolean compareAndSetRaw(long offset, long expect, long update) {
6.97 - return unsafe.compareAndSwapLong(array, offset, expect, update);
6.98 + if (array[i] == expect) {
6.99 + array[i] = update;
6.100 + return true;
6.101 + } else {
6.102 + return false;
6.103 + }
6.104 }
6.105
6.106 /**
6.107 @@ -217,12 +188,9 @@
6.108 * @return the previous value
6.109 */
6.110 public final long getAndAdd(int i, long delta) {
6.111 - long offset = checkedByteOffset(i);
6.112 - while (true) {
6.113 - long current = getRaw(offset);
6.114 - if (compareAndSetRaw(offset, current, current + delta))
6.115 - return current;
6.116 - }
6.117 + long v = array[i];
6.118 + array[i] += delta;
6.119 + return v;
6.120 }
6.121
6.122 /**
6.123 @@ -253,13 +221,8 @@
6.124 * @return the updated value
6.125 */
6.126 public long addAndGet(int i, long delta) {
6.127 - long offset = checkedByteOffset(i);
6.128 - while (true) {
6.129 - long current = getRaw(offset);
6.130 - long next = current + delta;
6.131 - if (compareAndSetRaw(offset, current, next))
6.132 - return next;
6.133 - }
6.134 + array[i] += delta;
6.135 + return array[i];
6.136 }
6.137
6.138 /**
6.139 @@ -274,7 +237,7 @@
6.140 StringBuilder b = new StringBuilder();
6.141 b.append('[');
6.142 for (int i = 0; ; i++) {
6.143 - b.append(getRaw(byteOffset(i)));
6.144 + b.append(get(i));
6.145 if (i == iMax)
6.146 return b.append(']').toString();
6.147 b.append(',').append(' ');
7.1 --- a/rt/emul/compact/src/main/java/java/util/concurrent/atomic/AtomicReference.java Thu Oct 03 17:36:44 2013 +0200
7.2 +++ b/rt/emul/compact/src/main/java/java/util/concurrent/atomic/AtomicReference.java Fri Oct 04 10:52:01 2013 +0200
7.3 @@ -34,7 +34,6 @@
7.4 */
7.5
7.6 package java.util.concurrent.atomic;
7.7 -import sun.misc.Unsafe;
7.8
7.9 /**
7.10 * An object reference that may be updated atomically. See the {@link
7.11 @@ -47,16 +46,6 @@
7.12 public class AtomicReference<V> implements java.io.Serializable {
7.13 private static final long serialVersionUID = -1848883965231344442L;
7.14
7.15 - private static final Unsafe unsafe = Unsafe.getUnsafe();
7.16 - private static final long valueOffset;
7.17 -
7.18 - static {
7.19 - try {
7.20 - valueOffset = unsafe.objectFieldOffset
7.21 - (AtomicReference.class.getDeclaredField("value"));
7.22 - } catch (Exception ex) { throw new Error(ex); }
7.23 - }
7.24 -
7.25 private volatile V value;
7.26
7.27 /**
7.28 @@ -99,7 +88,7 @@
7.29 * @since 1.6
7.30 */
7.31 public final void lazySet(V newValue) {
7.32 - unsafe.putOrderedObject(this, valueOffset, newValue);
7.33 + value = newValue;
7.34 }
7.35
7.36 /**
7.37 @@ -111,7 +100,12 @@
7.38 * the actual value was not equal to the expected value.
7.39 */
7.40 public final boolean compareAndSet(V expect, V update) {
7.41 - return unsafe.compareAndSwapObject(this, valueOffset, expect, update);
7.42 + if (value == expect) {
7.43 + value = update;
7.44 + return true;
7.45 + } else {
7.46 + return false;
7.47 + }
7.48 }
7.49
7.50 /**
7.51 @@ -127,7 +121,7 @@
7.52 * @return true if successful.
7.53 */
7.54 public final boolean weakCompareAndSet(V expect, V update) {
7.55 - return unsafe.compareAndSwapObject(this, valueOffset, expect, update);
7.56 + return compareAndSet(expect, update);
7.57 }
7.58
7.59 /**
8.1 --- a/rt/emul/compact/src/main/java/java/util/concurrent/atomic/AtomicReferenceArray.java Thu Oct 03 17:36:44 2013 +0200
8.2 +++ b/rt/emul/compact/src/main/java/java/util/concurrent/atomic/AtomicReferenceArray.java Fri Oct 04 10:52:01 2013 +0200
8.3 @@ -34,8 +34,6 @@
8.4 */
8.5
8.6 package java.util.concurrent.atomic;
8.7 -import sun.misc.Unsafe;
8.8 -import java.util.*;
8.9
8.10 /**
8.11 * An array of object references in which elements may be updated
8.12 @@ -49,29 +47,8 @@
8.13 public class AtomicReferenceArray<E> implements java.io.Serializable {
8.14 private static final long serialVersionUID = -6209656149925076980L;
8.15
8.16 - private static final Unsafe unsafe = Unsafe.getUnsafe();
8.17 - private static final int base = unsafe.arrayBaseOffset(Object[].class);
8.18 - private static final int shift;
8.19 private final Object[] array;
8.20
8.21 - static {
8.22 - int scale = unsafe.arrayIndexScale(Object[].class);
8.23 - if ((scale & (scale - 1)) != 0)
8.24 - throw new Error("data type scale not a power of two");
8.25 - shift = 31 - Integer.numberOfLeadingZeros(scale);
8.26 - }
8.27 -
8.28 - private long checkedByteOffset(int i) {
8.29 - if (i < 0 || i >= array.length)
8.30 - throw new IndexOutOfBoundsException("index " + i);
8.31 -
8.32 - return byteOffset(i);
8.33 - }
8.34 -
8.35 - private static long byteOffset(int i) {
8.36 - return ((long) i << shift) + base;
8.37 - }
8.38 -
8.39 /**
8.40 * Creates a new AtomicReferenceArray of the given length, with all
8.41 * elements initially null.
8.42 @@ -110,11 +87,7 @@
8.43 * @return the current value
8.44 */
8.45 public final E get(int i) {
8.46 - return getRaw(checkedByteOffset(i));
8.47 - }
8.48 -
8.49 - private E getRaw(long offset) {
8.50 - return (E) unsafe.getObjectVolatile(array, offset);
8.51 + return (E)array[i];
8.52 }
8.53
8.54 /**
8.55 @@ -124,7 +97,7 @@
8.56 * @param newValue the new value
8.57 */
8.58 public final void set(int i, E newValue) {
8.59 - unsafe.putObjectVolatile(array, checkedByteOffset(i), newValue);
8.60 + array[i] = newValue;
8.61 }
8.62
8.63 /**
8.64 @@ -135,7 +108,7 @@
8.65 * @since 1.6
8.66 */
8.67 public final void lazySet(int i, E newValue) {
8.68 - unsafe.putOrderedObject(array, checkedByteOffset(i), newValue);
8.69 + array[i] = newValue;
8.70 }
8.71
8.72
8.73 @@ -148,12 +121,9 @@
8.74 * @return the previous value
8.75 */
8.76 public final E getAndSet(int i, E newValue) {
8.77 - long offset = checkedByteOffset(i);
8.78 - while (true) {
8.79 - E current = (E) getRaw(offset);
8.80 - if (compareAndSetRaw(offset, current, newValue))
8.81 - return current;
8.82 - }
8.83 + E v = (E)array[i];
8.84 + array[i] = newValue;
8.85 + return v;
8.86 }
8.87
8.88 /**
8.89 @@ -167,11 +137,12 @@
8.90 * the actual value was not equal to the expected value.
8.91 */
8.92 public final boolean compareAndSet(int i, E expect, E update) {
8.93 - return compareAndSetRaw(checkedByteOffset(i), expect, update);
8.94 - }
8.95 -
8.96 - private boolean compareAndSetRaw(long offset, E expect, E update) {
8.97 - return unsafe.compareAndSwapObject(array, offset, expect, update);
8.98 + if (array[i] == expect) {
8.99 + array[i] = update;
8.100 + return true;
8.101 + } else {
8.102 + return false;
8.103 + }
8.104 }
8.105
8.106 /**
8.107 @@ -203,7 +174,7 @@
8.108 StringBuilder b = new StringBuilder();
8.109 b.append('[');
8.110 for (int i = 0; ; i++) {
8.111 - b.append(getRaw(byteOffset(i)));
8.112 + b.append(get(i));
8.113 if (i == iMax)
8.114 return b.append(']').toString();
8.115 b.append(',').append(' ');
9.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
9.2 +++ b/rt/emul/compact/src/test/java/org/apidesign/bck2brwsr/tck/AtomicTest.java Fri Oct 04 10:52:01 2013 +0200
9.3 @@ -0,0 +1,54 @@
9.4 +/**
9.5 + * Back 2 Browser Bytecode Translator
9.6 + * Copyright (C) 2012 Jaroslav Tulach <jaroslav.tulach@apidesign.org>
9.7 + *
9.8 + * This program is free software: you can redistribute it and/or modify
9.9 + * it under the terms of the GNU General Public License as published by
9.10 + * the Free Software Foundation, version 2 of the License.
9.11 + *
9.12 + * This program is distributed in the hope that it will be useful,
9.13 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
9.14 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
9.15 + * GNU General Public License for more details.
9.16 + *
9.17 + * You should have received a copy of the GNU General Public License
9.18 + * along with this program. Look for COPYING file in the top folder.
9.19 + * If not, see http://opensource.org/licenses/GPL-2.0.
9.20 + */
9.21 +package org.apidesign.bck2brwsr.tck;
9.22 +
9.23 +import java.util.concurrent.atomic.AtomicBoolean;
9.24 +import java.util.concurrent.atomic.AtomicInteger;
9.25 +import java.util.concurrent.atomic.AtomicReference;
9.26 +import org.apidesign.bck2brwsr.vmtest.Compare;
9.27 +import org.apidesign.bck2brwsr.vmtest.VMTest;
9.28 +import org.testng.annotations.Factory;
9.29 +
9.30 +/**
9.31 + *
9.32 + * @author Jaroslav Tulach <jtulach@netbeans.org>
9.33 + */
9.34 +public class AtomicTest {
9.35 + @Compare public boolean atomicBoolean() {
9.36 + AtomicBoolean ab = new AtomicBoolean();
9.37 + ab.set(true);
9.38 + return ab.compareAndSet(true, false);
9.39 + }
9.40 +
9.41 + @Compare public int atomicInt() {
9.42 + AtomicInteger ab = new AtomicInteger();
9.43 + ab.set(30);
9.44 + assert ab.compareAndSet(30, 10);
9.45 + return ab.get();
9.46 + }
9.47 +
9.48 + @Compare public String atomicRef() {
9.49 + AtomicReference<String> ar = new AtomicReference<String>("Ahoj");
9.50 + assert ar.compareAndSet("Ahoj", "Hello");
9.51 + return ar.getAndSet("Other");
9.52 + }
9.53 +
9.54 + @Factory public static Object[] create() {
9.55 + return VMTest.create(AtomicTest.class);
9.56 + }
9.57 +}
10.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
10.2 +++ b/rt/emul/compact/src/test/java/org/apidesign/bck2brwsr/tck/ConcurrentTest.java Fri Oct 04 10:52:01 2013 +0200
10.3 @@ -0,0 +1,40 @@
10.4 +/**
10.5 + * Back 2 Browser Bytecode Translator
10.6 + * Copyright (C) 2012 Jaroslav Tulach <jaroslav.tulach@apidesign.org>
10.7 + *
10.8 + * This program is free software: you can redistribute it and/or modify
10.9 + * it under the terms of the GNU General Public License as published by
10.10 + * the Free Software Foundation, version 2 of the License.
10.11 + *
10.12 + * This program is distributed in the hope that it will be useful,
10.13 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
10.14 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10.15 + * GNU General Public License for more details.
10.16 + *
10.17 + * You should have received a copy of the GNU General Public License
10.18 + * along with this program. Look for COPYING file in the top folder.
10.19 + * If not, see http://opensource.org/licenses/GPL-2.0.
10.20 + */
10.21 +package org.apidesign.bck2brwsr.tck;
10.22 +
10.23 +import java.util.concurrent.ConcurrentHashMap;
10.24 +import org.apidesign.bck2brwsr.vmtest.Compare;
10.25 +import org.apidesign.bck2brwsr.vmtest.VMTest;
10.26 +import org.testng.annotations.Factory;
10.27 +
10.28 +/**
10.29 + *
10.30 + * @author Jaroslav Tulach <jtulach@netbeans.org>
10.31 + */
10.32 +public class ConcurrentTest {
10.33 + @Compare public String mapIfAbsent() {
10.34 + ConcurrentHashMap<String,String> m = new ConcurrentHashMap<>();
10.35 + m.putIfAbsent("Ahoj", "Jardo");
10.36 + m.putIfAbsent("Ahoj", "Dardo");
10.37 + return m.get("Ahoj");
10.38 + }
10.39 +
10.40 + @Factory public static Object[] create() {
10.41 + return VMTest.create(ConcurrentTest.class);
10.42 + }
10.43 +}