--- jsr166/src/extra166y/CustomConcurrentHashMap.java 2009/11/02 11:47:36 1.7 +++ jsr166/src/extra166y/CustomConcurrentHashMap.java 2013/01/19 21:37:46 1.29 @@ -1,7 +1,7 @@ /* * Written by Doug Lea with assistance from members of JCP JSR-166 * Expert Group and released to the public domain, as explained at - * http://creativecommons.org/licenses/publicdomain + * http://creativecommons.org/publicdomain/zero/1.0/ */ package extra166y; @@ -25,15 +25,15 @@ import sun.misc.Unsafe; *
  • {@linkplain SoftReference Soft}, {@linkplain * WeakReference weak} or strong (regular) keys and values. * - *
  • User-definable MappingFunctions that may be + *
  • User-definable {@code MappingFunctions} that may be * used in method {@link * CustomConcurrentHashMap#computeIfAbsent} to atomically * establish a computed value, along with - * RemappingFunctions that can be used in method + * {@code RemappingFunctions} that can be used in method * {@link CustomConcurrentHashMap#compute} to atomically * replace values. * - *
  • Factory methods returning specialized forms for int + *
  • Factory methods returning specialized forms for {@code int} * keys and/or values, that may be more space-efficient * * @@ -53,10 +53,10 @@ import sun.misc.Unsafe; * (STRONG, * new Equivalence() { * public boolean equal(Person k, Object x) { - * return x instanceOf Person && k.name.equals(((Person)x).name); + * return x instanceof Person && k.name.equals(((Person)x).name); * } * public int hash(Object x) { - * return (x instanceOf Person)? ((Person)x).name.hashCode() : 0; + * return (x instanceof Person) ? ((Person)x).name.hashCode() : 0; * } * }, * STRONG, EQUALS, 0); @@ -72,24 +72,24 @@ import sun.misc.Unsafe; * *

    This class also includes nested class {@link KeySet} * that provides space-efficient Set views of maps, also supporting - * method intern, which may be of use in canonicalizing + * method {@code intern}, which may be of use in canonicalizing * elements. * *

    When used with (Weak or Soft) Reference keys and/or values, - * elements that have asynchronously become null are + * elements that have asynchronously become {@code null} are * treated as absent from the map and (eventually) removed from maps * via a background thread common across all maps. Because of the * potential for asynchronous clearing of References, methods such as - * containsValue have weaker guarantees than you might + * {@code containsValue} have weaker guarantees than you might * expect even in the absence of other explicitly concurrent - * operations. For example containsValue(value) may - * return true even if value is no longer available upon + * operations. For example {@code containsValue(value)} may + * return true even if {@code value} is no longer available upon * return from the method. * *

    When Equivalences other than equality are used, the returned - * collections may violate the specifications of Map and/or - * Set interfaces, which mandate the use of the - * equals method when comparing objects. The methods of this + * collections may violate the specifications of {@code Map} and/or + * {@code Set} interfaces, which mandate the use of the + * {@code equals} method when comparing objects. The methods of this * class otherwise have properties similar to those of {@link * java.util.ConcurrentHashMap} under its default settings. To * adaptively maintain semantics and performance under varying @@ -165,8 +165,8 @@ public class CustomConcurrentHashMapK may be - * entered into a Map, any Object may be tested for + * java.util.Map}: While only elements of {@code K} may be + * entered into a Map, any {@code Object} may be tested for * membership. Note that the performance of hash maps is heavily * dependent on the quality of hash functions. */ @@ -224,7 +224,7 @@ public class CustomConcurrentHashMapnull if there is no mapping. + * or {@code null} if there is no mapping. */ public static interface MappingFunction { /** @@ -236,7 +236,7 @@ public class CustomConcurrentHashMapnull if there is + * current value to a new value, or {@code null} if there is * no mapping */ public static interface RemappingFunction { @@ -320,7 +320,7 @@ public class CustomConcurrentHashMap= MAX_SEGMENT_CAPACITY) return oldTable; - Node[] newTable = - (Node[])new Node[oldCapacity<<1]; + Node[] newTable = new Node[oldCapacity<<1]; int sizeMask = newTable.length - 1; NodeFactory fac = cchm.factory; for (int i = 0; i < oldCapacity ; i++) { @@ -537,14 +535,14 @@ public class CustomConcurrentHashMap MAX_SEGMENT_CAPACITY) - capacity = MAX_SEGMENT_CAPACITY; + capacity = MAX_SEGMENT_CAPACITY; this.initialSegmentCapacity = capacity; } - this.segments = (Segment[])new Segment[NSEGMENTS]; + this.segments = new Segment[NSEGMENTS]; } /** - * Creates a new CustomConcurrentHashMap with the given parameters + * Creates a new CustomConcurrentHashMap with the given parameters. * @param keyStrength the strength for keys * @param keyEquivalence the Equivalence to use for keys * @param valueStrength the strength for values @@ -573,7 +571,7 @@ public class CustomConcurrentHashMap>> SEGMENT_SHIFT) & SEGMENT_MASK; Segment seg = segs[index]; if (seg == null) { - synchronized(segs) { + synchronized (segs) { seg = segs[index]; if (seg == null) { seg = new Segment(); @@ -656,7 +654,7 @@ public class CustomConcurrentHashMaptrue if this map contains a key equivalent to + * Returns {@code true} if this map contains a key equivalent to * the given key with respect to this map's key Equivalence. * * @param key possible key - * @return true if this map contains the specified key + * @return {@code true} if this map contains the specified key * @throws NullPointerException if the specified key is null */ public boolean containsKey(Object key) { @@ -697,10 +695,10 @@ public class CustomConcurrentHashMapnull if + * @return the value associated with the key or {@code null} if * there is no mapping. * @throws NullPointerException if the specified key is null */ @@ -752,8 +750,8 @@ public class CustomConcurrentHashMapkey, or - * null if there was no mapping for key + * @return the previous value associated with {@code key}, or + * {@code null} if there was no mapping for {@code key} * @throws NullPointerException if the specified key or value is null */ public V put(K key, V value) { @@ -764,7 +762,7 @@ public class CustomConcurrentHashMapnull if there was no mapping for the key + * or {@code null} if there was no mapping for the key * @throws NullPointerException if the specified key or value is null */ public V putIfAbsent(K key, V value) { @@ -813,7 +811,7 @@ public class CustomConcurrentHashMapnull if there was no mapping for the key + * or {@code null} if there was no mapping for the key * @throws NullPointerException if the specified key or value is null */ public boolean replace(K key, V oldValue, V newValue) { @@ -845,8 +843,8 @@ public class CustomConcurrentHashMapkey, or - * null if there was no mapping for key + * @return the previous value associated with {@code key}, or + * {@code null} if there was no mapping for {@code key} * @throws NullPointerException if the specified key is null */ public V remove(Object key) { @@ -942,7 +940,7 @@ public class CustomConcurrentHashMaptrue if this map contains no key-value mappings. + * Returns {@code true} if this map contains no key-value mappings. * - * @return true if this map contains no key-value mappings + * @return {@code true} if this map contains no key-value mappings */ public final boolean isEmpty() { final Segment[] segs = this.segments; @@ -997,8 +995,8 @@ public class CustomConcurrentHashMapInteger.MAX_VALUE elements, returns - * Integer.MAX_VALUE. + * map contains more than {@code Integer.MAX_VALUE} elements, returns + * {@code Integer.MAX_VALUE}. * * @return the number of key-value mappings in this map */ @@ -1010,18 +1008,18 @@ public class CustomConcurrentHashMap= Integer.MAX_VALUE? Integer.MAX_VALUE : (int)sum; + return (sum >= Integer.MAX_VALUE) ? Integer.MAX_VALUE : (int) sum; } /** - * Returns true if this map maps one or more keys to a + * Returns {@code true} if this map maps one or more keys to a * value equivalent to the given value with respect to this map's * value Equivalence. Note: This method requires a full internal * traversal of the hash table, and so is much slower than method - * containsKey. + * {@code containsKey}. * * @param value value whose presence in this map is to be tested - * @return true if this map maps one or more keys to the + * @return {@code true} if this map maps one or more keys to the * specified value * @throws NullPointerException if the specified value is null */ @@ -1069,7 +1067,7 @@ public class CustomConcurrentHashMap * if (map.containsKey(key)) @@ -1091,8 +1089,8 @@ public class CustomConcurrentHashMapnull if the computation - * returned null. + * the specified key, or {@code null} if the computation + * returned {@code null}. * @throws NullPointerException if the specified key or mappingFunction * is null, * @throws RuntimeException or Error if the mappingFunction does so, @@ -1158,14 +1156,14 @@ public class CustomConcurrentHashMap * map.compute(word, new RemappingFunction<String,Integer>() { * public Integer remap(String k, Integer v) { - * return v == null? 1 : v + 1; + * return (v == null) ? 1 : v + 1; * }}); * * * @param key key with which the specified value is to be associated * @param remappingFunction the function to compute a value * @return the updated value or - * null if the computation returned null + * {@code null} if the computation returned {@code null} * @throws NullPointerException if the specified key or remappingFunction * is null, * @throws RuntimeException or Error if the remappingFunction does so, @@ -1414,7 +1412,8 @@ public class CustomConcurrentHashMap e = (Map.Entry)o; - return CustomConcurrentHashMap.this.remove(e.getKey(), e.getValue()); + return CustomConcurrentHashMap.this.remove(e.getKey(), + e.getValue()); } public int size() { return CustomConcurrentHashMap.this.size(); @@ -1432,12 +1431,12 @@ public class CustomConcurrentHashMapIterator.remove, Set.remove, - * removeAll, retainAll, and clear - * operations. It does not support the add or - * addAll operations. + * via the {@code Iterator.remove}, {@code Set.remove}, + * {@code removeAll}, {@code retainAll}, and {@code clear} + * operations. It does not support the {@code add} or + * {@code addAll} operations. * - *

    The view's iterator is a "weakly consistent" iterator + *

    The view's {@code iterator} is a "weakly consistent" iterator * that will never throw {@link ConcurrentModificationException}, * and guarantees to traverse elements as they existed upon * construction of the iterator, and may (but is not guaranteed to) @@ -1453,12 +1452,12 @@ public class CustomConcurrentHashMapIterator.remove, - * Collection.remove, removeAll, - * retainAll, and clear operations. It does not - * support the add or addAll operations. + * mapping from this map, via the {@code Iterator.remove}, + * {@code Collection.remove}, {@code removeAll}, + * {@code retainAll}, and {@code clear} operations. It does not + * support the {@code add} or {@code addAll} operations. * - *

    The view's iterator is a "weakly consistent" iterator + *

    The view's {@code iterator} is a "weakly consistent" iterator * that will never throw {@link ConcurrentModificationException}, * and guarantees to traverse elements as they existed upon * construction of the iterator, and may (but is not guaranteed to) @@ -1474,12 +1473,12 @@ public class CustomConcurrentHashMapIterator.remove, Set.remove, - * removeAll, retainAll, and clear - * operations. It does not support the add or - * addAll operations. + * via the {@code Iterator.remove}, {@code Set.remove}, + * {@code removeAll}, {@code retainAll}, and {@code clear} + * operations. It does not support the {@code add} or + * {@code addAll} operations. * - *

    The view's iterator is a "weakly consistent" iterator + *

    The view's {@code iterator} is a "weakly consistent" iterator * that will never throw {@link ConcurrentModificationException}, * and guarantees to traverse elements as they existed upon * construction of the iterator, and may (but is not guaranteed to) @@ -1494,13 +1493,13 @@ public class CustomConcurrentHashMaptrue if the given object is also a map of the + * Returns {@code true} if the given object is also a map of the * same size, holding keys that are equal using this Map's key * Equivalence, and which map to values that are equal according * to this Map's value equivalence. * * @param o object to be compared for equality with this map - * @return true if the specified object is equal to this map + * @return {@code true} if the specified object is equal to this map */ public boolean equals(Object o) { if (o == this) @@ -1537,7 +1536,7 @@ public class CustomConcurrentHashMapentrySet() view, which in turn are the hash codes + * {@code entrySet()} view, which in turn are the hash codes * computed using key and value Equivalences for this Map. * @return the hash code */ @@ -1550,15 +1549,15 @@ public class CustomConcurrentHashMap e : entrySet()) { s.writeObject(e.getKey()); @@ -1569,13 +1568,13 @@ public class CustomConcurrentHashMapCollections.newSetFromMap applied to a - * CustomConcurrentHashMap, but possibly more + * {@code Collections.newSetFromMap} applied to a + * {@code CustomConcurrentHashMap}, but possibly more * space-efficient. The set does not permit null elements. The * set is serializable; however, serializing a set that uses soft * or weak references can give unpredictable results. @@ -1599,7 +1598,7 @@ public class CustomConcurrentHashMap cchm; /** - * Creates a set with the given parameters + * Creates a set with the given parameters. * @param strength the strength of elements * @param equivalence the Equivalence to use * @param expectedSize an estimate of the number of elements @@ -1620,7 +1619,7 @@ public class CustomConcurrentHashMaptrue if this set contains an + * Returns {@code true} if this set contains an * element equivalent to the given element with respect * to this set's Equivalence. * @param o element whose presence in this set is to be tested - * @return true if this set contains the specified element + * @return {@code true} if this set contains the specified element */ public boolean contains(Object o) { return cchm.containsKey(o); @@ -1655,7 +1654,7 @@ public class CustomConcurrentHashMaptrue if this set did not already contain + * @return {@code true} if this set did not already contain * the specified element */ public boolean add(K e) { @@ -1667,16 +1666,16 @@ public class CustomConcurrentHashMaptrue if the set contained the specified element + * @return {@code true} if the set contained the specified element */ public boolean remove(Object o) { return cchm.remove(o) != null; } /** - * Returns true if this set contains no elements. + * Returns {@code true} if this set contains no elements. * - * @return true if this set contains no elements + * @return {@code true} if this set contains no elements */ public boolean isEmpty() { return cchm.isEmpty(); @@ -1792,7 +1791,7 @@ public class CustomConcurrentHashMap() { - public Unsafe run() throws Exception { - return getUnsafePrivileged(); - }}); - } catch (java.security.PrivilegedActionException e) { - throw e.getCause(); - } - } - } - - private static Unsafe getUnsafePrivileged() - throws NoSuchFieldException, IllegalAccessException { - Field f = Unsafe.class.getDeclaredField("theUnsafe"); - f.setAccessible(true); - return (Unsafe) f.get(null); - } - static { try { - _unsafe = getUnsafe(); - tableBase = _unsafe.arrayBaseOffset(Node[].class); - int s = _unsafe.arrayIndexScale(Node[].class); - if ((s & (s-1)) != 0) + UNSAFE = getUnsafe(); + tableBase = UNSAFE.arrayBaseOffset(Node[].class); + int scale = UNSAFE.arrayIndexScale(Node[].class); + if ((scale & (scale - 1)) != 0) throw new Error("data type scale not a power of two"); - tableShift = 31 - Integer.numberOfLeadingZeros(s); - segmentsBase = _unsafe.arrayBaseOffset(Segment[].class); - s = _unsafe.arrayIndexScale(Segment[].class); - if ((s & (s-1)) != 0) + tableShift = 31 - Integer.numberOfLeadingZeros(scale); + segmentsBase = UNSAFE.arrayBaseOffset(Segment[].class); + scale = UNSAFE.arrayIndexScale(Segment[].class); + if ((scale & (scale - 1)) != 0) throw new Error("data type scale not a power of two"); - segmentsShift = 31 - Integer.numberOfLeadingZeros(s); + segmentsShift = 31 - Integer.numberOfLeadingZeros(scale); } catch (Throwable e) { throw new RuntimeException("Could not initialize intrinsics", e); } } // Fenced store into segment table array. Unneeded when we have Fences - static final void storeNode(Node[] table, - int i, Node r) { + static final void storeNode(Node[] table, + int i, Node r) { long nodeOffset = ((long) i << tableShift) + tableBase; - _unsafe.putOrderedObject(table, nodeOffset, r); + UNSAFE.putOrderedObject(table, nodeOffset, r); } - static final void storeSegment(Segment[] segs, - int i, Segment s) { + static final void storeSegment(Segment[] segs, + int i, Segment s) { long segmentOffset = ((long) i << segmentsShift) + segmentsBase; - _unsafe.putOrderedObject(segs, segmentOffset, s); + UNSAFE.putOrderedObject(segs, segmentOffset, s); } - + /** + * Returns a sun.misc.Unsafe. Suitable for use in a 3rd party package. + * Replace with a simple call to Unsafe.getUnsafe when integrating + * into a jdk. + * + * @return a sun.misc.Unsafe + */ + private static sun.misc.Unsafe getUnsafe() { + try { + return sun.misc.Unsafe.getUnsafe(); + } catch (SecurityException tryReflectionInstead) {} + try { + return java.security.AccessController.doPrivileged + (new java.security.PrivilegedExceptionAction() { + public sun.misc.Unsafe run() throws Exception { + Class k = sun.misc.Unsafe.class; + for (java.lang.reflect.Field f : k.getDeclaredFields()) { + f.setAccessible(true); + Object x = f.get(null); + if (k.isInstance(x)) + return k.cast(x); + } + throw new NoSuchFieldError("the Unsafe"); + }}); + } catch (java.security.PrivilegedActionException e) { + throw new RuntimeException("Could not initialize intrinsics", + e.getCause()); + } + } }