src/share/classes/java/util/concurrent/ConcurrentHashMap.java

Print this page

        

*** 35,47 **** package java.util.concurrent; import java.util.concurrent.locks.*; import java.util.*; import java.io.Serializable; - import java.io.IOException; - import java.io.ObjectInputStream; - import java.io.ObjectOutputStream; /** * A hash table supporting full concurrency of retrievals and * adjustable expected concurrency for updates. This class obeys the * same functional specification as {@link java.util.Hashtable}, and --- 35,44 ----
*** 226,236 **** static final sun.misc.Unsafe UNSAFE; static final long nextOffset; static { try { UNSAFE = sun.misc.Unsafe.getUnsafe(); ! Class k = HashEntry.class; nextOffset = UNSAFE.objectFieldOffset (k.getDeclaredField("next")); } catch (Exception e) { throw new Error(e); } --- 223,233 ---- static final sun.misc.Unsafe UNSAFE; static final long nextOffset; static { try { UNSAFE = sun.misc.Unsafe.getUnsafe(); ! Class<?> k = HashEntry.class; nextOffset = UNSAFE.objectFieldOffset (k.getDeclaredField("next")); } catch (Exception e) { throw new Error(e); }
*** 431,441 **** HashEntry<K,V>[] oldTable = table; int oldCapacity = oldTable.length; int newCapacity = oldCapacity << 1; threshold = (int)(newCapacity * loadFactor); HashEntry<K,V>[] newTable = ! (HashEntry<K,V>[]) new HashEntry[newCapacity]; int sizeMask = newCapacity - 1; for (int i = 0; i < oldCapacity ; i++) { HashEntry<K,V> e = oldTable[i]; if (e != null) { HashEntry<K,V> next = e.next; --- 428,438 ---- HashEntry<K,V>[] oldTable = table; int oldCapacity = oldTable.length; int newCapacity = oldCapacity << 1; threshold = (int)(newCapacity * loadFactor); HashEntry<K,V>[] newTable = ! (HashEntry<K,V>[]) new HashEntry<?,?>[newCapacity]; int sizeMask = newCapacity - 1; for (int i = 0; i < oldCapacity ; i++) { HashEntry<K,V> e = oldTable[i]; if (e != null) { HashEntry<K,V> next = e.next;
*** 675,685 **** if ((seg = (Segment<K,V>)UNSAFE.getObjectVolatile(ss, u)) == null) { Segment<K,V> proto = ss[0]; // use segment 0 as prototype int cap = proto.table.length; float lf = proto.loadFactor; int threshold = (int)(cap * lf); ! HashEntry<K,V>[] tab = (HashEntry<K,V>[])new HashEntry[cap]; if ((seg = (Segment<K,V>)UNSAFE.getObjectVolatile(ss, u)) == null) { // recheck Segment<K,V> s = new Segment<K,V>(lf, threshold, tab); while ((seg = (Segment<K,V>)UNSAFE.getObjectVolatile(ss, u)) == null) { --- 672,682 ---- if ((seg = (Segment<K,V>)UNSAFE.getObjectVolatile(ss, u)) == null) { Segment<K,V> proto = ss[0]; // use segment 0 as prototype int cap = proto.table.length; float lf = proto.loadFactor; int threshold = (int)(cap * lf); ! HashEntry<K,V>[] tab = (HashEntry<K,V>[])new HashEntry<?,?>[cap]; if ((seg = (Segment<K,V>)UNSAFE.getObjectVolatile(ss, u)) == null) { // recheck Segment<K,V> s = new Segment<K,V>(lf, threshold, tab); while ((seg = (Segment<K,V>)UNSAFE.getObjectVolatile(ss, u)) == null) {
*** 692,711 **** } // Hash-based segment and entry accesses /** ! * Get the segment for the given hash */ @SuppressWarnings("unchecked") private Segment<K,V> segmentForHash(int h) { long u = (((h >>> segmentShift) & segmentMask) << SSHIFT) + SBASE; return (Segment<K,V>) UNSAFE.getObjectVolatile(segments, u); } /** ! * Gets the table entry for the given segment and hash */ @SuppressWarnings("unchecked") static final <K,V> HashEntry<K,V> entryForHash(Segment<K,V> seg, int h) { HashEntry<K,V>[] tab; return (seg == null || (tab = seg.table) == null) ? null : --- 689,708 ---- } // Hash-based segment and entry accesses /** ! * Gets the segment for the given hash code. */ @SuppressWarnings("unchecked") private Segment<K,V> segmentForHash(int h) { long u = (((h >>> segmentShift) & segmentMask) << SSHIFT) + SBASE; return (Segment<K,V>) UNSAFE.getObjectVolatile(segments, u); } /** ! * Gets the table entry for the given segment and hash code. */ @SuppressWarnings("unchecked") static final <K,V> HashEntry<K,V> entryForHash(Segment<K,V> seg, int h) { HashEntry<K,V>[] tab; return (seg == null || (tab = seg.table) == null) ? null :
*** 756,767 **** while (cap < c) cap <<= 1; // create segments and segments[0] Segment<K,V> s0 = new Segment<K,V>(loadFactor, (int)(cap * loadFactor), ! (HashEntry<K,V>[])new HashEntry[cap]); ! Segment<K,V>[] ss = (Segment<K,V>[])new Segment[ssize]; UNSAFE.putOrderedObject(ss, SBASE, s0); // ordered write of segments[0] this.segments = ss; } /** --- 753,764 ---- while (cap < c) cap <<= 1; // create segments and segments[0] Segment<K,V> s0 = new Segment<K,V>(loadFactor, (int)(cap * loadFactor), ! (HashEntry<K,V>[])new HashEntry<?,?>[cap]); ! Segment<K,V>[] ss = (Segment<K,V>[])new Segment<?,?>[ssize]; UNSAFE.putOrderedObject(ss, SBASE, s0); // ordered write of segments[0] this.segments = ss; } /**
*** 914,923 **** --- 911,921 ---- * then this method returns {@code v}; otherwise it returns * {@code null}. (There can be at most one such mapping.) * * @throws NullPointerException if the specified key is null */ + @SuppressWarnings("unchecked") public V get(Object key) { Segment<K,V> s; // manually integrate access methods to reduce overhead HashEntry<K,V>[] tab; int h = hash(key.hashCode()); long u = (((h >>> segmentShift) & segmentMask) << SSHIFT) + SBASE;
*** 1024,1034 **** * in this table. This method is identical in functionality to * {@link #containsValue}, and exists solely to ensure * full compatibility with class {@link java.util.Hashtable}, * which supported this method prior to introduction of the * Java Collections framework. ! * @param value a value to search for * @return <tt>true</tt> if and only if some key maps to the * <tt>value</tt> argument in this table as * determined by the <tt>equals</tt> method; * <tt>false</tt> otherwise --- 1022,1032 ---- * in this table. This method is identical in functionality to * {@link #containsValue}, and exists solely to ensure * full compatibility with class {@link java.util.Hashtable}, * which supported this method prior to introduction of the * Java Collections framework. ! * * @param value a value to search for * @return <tt>true</tt> if and only if some key maps to the * <tt>value</tt> argument in this table as * determined by the <tt>equals</tt> method; * <tt>false</tt> otherwise
*** 1260,1270 **** nextTableIndex = -1; advance(); } /** ! * Set nextEntry to first node of next non-empty table * (in backwards order, to simplify checks). */ final void advance() { for (;;) { if (nextTableIndex >= 0) { --- 1258,1268 ---- nextTableIndex = -1; advance(); } /** ! * Sets nextEntry to first node of next non-empty table * (in backwards order, to simplify checks). */ final void advance() { for (;;) { if (nextTableIndex >= 0) {
*** 1324,1339 **** * setValue changes to the underlying map. */ final class WriteThroughEntry extends AbstractMap.SimpleEntry<K,V> { WriteThroughEntry(K k, V v) { super(k,v); } /** ! * Set our entry's value and write through to the map. The * value to return is somewhat arbitrary here. Since a * WriteThroughEntry does not necessarily track asynchronous * changes, the most recent "previous" value could be * different from what we return (or could even have been * removed in which case the put will re-establish). We do not --- 1322,1339 ---- * setValue changes to the underlying map. */ final class WriteThroughEntry extends AbstractMap.SimpleEntry<K,V> { + static final long serialVersionUID = 7249069246763182397L; + WriteThroughEntry(K k, V v) { super(k,v); } /** ! * Sets our entry's value and writes through to the map. The * value to return is somewhat arbitrary here. Since a * WriteThroughEntry does not necessarily track asynchronous * changes, the most recent "previous" value could be * different from what we return (or could even have been * removed in which case the put will re-establish). We do not
*** 1425,1443 **** } /* ---------------- Serialization Support -------------- */ /** ! * Save the state of the <tt>ConcurrentHashMap</tt> instance to a ! * stream (i.e., serialize it). * @param s the stream * @serialData * the key (Object) and value (Object) * for each key-value mapping, followed by a null pair. * The key-value mappings are emitted in no particular order. */ ! private void writeObject(java.io.ObjectOutputStream s) throws IOException { // force all segments for serialization compatibility for (int k = 0; k < segments.length; ++k) ensureSegment(k); s.defaultWriteObject(); --- 1425,1444 ---- } /* ---------------- Serialization Support -------------- */ /** ! * Saves the state of the <tt>ConcurrentHashMap</tt> instance to a ! * stream (i.e., serializes it). * @param s the stream * @serialData * the key (Object) and value (Object) * for each key-value mapping, followed by a null pair. * The key-value mappings are emitted in no particular order. */ ! private void writeObject(java.io.ObjectOutputStream s) ! throws java.io.IOException { // force all segments for serialization compatibility for (int k = 0; k < segments.length; ++k) ensureSegment(k); s.defaultWriteObject();
*** 1461,1487 **** s.writeObject(null); s.writeObject(null); } /** ! * Reconstitute the <tt>ConcurrentHashMap</tt> instance from a ! * stream (i.e., deserialize it). * @param s the stream */ @SuppressWarnings("unchecked") private void readObject(java.io.ObjectInputStream s) ! throws IOException, ClassNotFoundException { s.defaultReadObject(); // Re-initialize segments to be minimally sized, and let grow. int cap = MIN_SEGMENT_TABLE_CAPACITY; final Segment<K,V>[] segments = this.segments; for (int k = 0; k < segments.length; ++k) { Segment<K,V> seg = segments[k]; if (seg != null) { seg.threshold = (int)(cap * seg.loadFactor); ! seg.table = (HashEntry<K,V>[]) new HashEntry[cap]; } } // Read the keys and values, and put the mappings in the table for (;;) { --- 1462,1488 ---- s.writeObject(null); s.writeObject(null); } /** ! * Reconstitutes the <tt>ConcurrentHashMap</tt> instance from a ! * stream (i.e., deserializes it). * @param s the stream */ @SuppressWarnings("unchecked") private void readObject(java.io.ObjectInputStream s) ! throws java.io.IOException, ClassNotFoundException { s.defaultReadObject(); // Re-initialize segments to be minimally sized, and let grow. int cap = MIN_SEGMENT_TABLE_CAPACITY; final Segment<K,V>[] segments = this.segments; for (int k = 0; k < segments.length; ++k) { Segment<K,V> seg = segments[k]; if (seg != null) { seg.threshold = (int)(cap * seg.loadFactor); ! seg.table = (HashEntry<K,V>[]) new HashEntry<?,?>[cap]; } } // Read the keys and values, and put the mappings in the table for (;;) {
*** 1502,1513 **** static { int ss, ts; try { UNSAFE = sun.misc.Unsafe.getUnsafe(); ! Class tc = HashEntry[].class; ! Class sc = Segment[].class; TBASE = UNSAFE.arrayBaseOffset(tc); SBASE = UNSAFE.arrayBaseOffset(sc); ts = UNSAFE.arrayIndexScale(tc); ss = UNSAFE.arrayIndexScale(sc); } catch (Exception e) { --- 1503,1514 ---- static { int ss, ts; try { UNSAFE = sun.misc.Unsafe.getUnsafe(); ! Class<?> tc = HashEntry[].class; ! Class<?> sc = Segment[].class; TBASE = UNSAFE.arrayBaseOffset(tc); SBASE = UNSAFE.arrayBaseOffset(sc); ts = UNSAFE.arrayIndexScale(tc); ss = UNSAFE.arrayIndexScale(sc); } catch (Exception e) {