一、前言
基于springframework的org.springframework.util.ConcurrentReferenceHashMap的类似java.util.concurrent.ConcurrentHashMap的实现java.util.concurrent.ConcurrentMap接口和java.util.AbstractMap抽象类。
二、源码说明
package org.springframework.util;@b@@b@import java.lang.ref.ReferenceQueue;@b@import java.lang.ref.SoftReference;@b@import java.lang.ref.WeakReference;@b@import java.lang.reflect.Array;@b@import java.util.AbstractMap;@b@import java.util.AbstractSet;@b@import java.util.Collections;@b@import java.util.EnumSet;@b@import java.util.HashSet;@b@import java.util.Iterator;@b@import java.util.Map.Entry;@b@import java.util.NoSuchElementException;@b@import java.util.Set;@b@import java.util.concurrent.ConcurrentMap;@b@import java.util.concurrent.locks.ReentrantLock;@b@@b@public class ConcurrentReferenceHashMap<K, V> extends AbstractMap<K, V>@b@ implements ConcurrentMap<K, V>@b@{@b@ private static final int DEFAULT_INITIAL_CAPACITY = 16;@b@ private static final float DEFAULT_LOAD_FACTOR = 0.75F;@b@ private static final int DEFAULT_CONCURRENCY_LEVEL = 16;@b@ private static final ReferenceType DEFAULT_REFERENCE_TYPE = ReferenceType.SOFT;@b@ private static final int MAXIMUM_CONCURRENCY_LEVEL = 65536;@b@ private static final int MAXIMUM_SEGMENT_SIZE = 1073741824;@b@ private final ConcurrentReferenceHashMap<K, V>[].Segment[] segments;@b@ private final float loadFactor;@b@ private final ReferenceType referenceType;@b@ private final int shift;@b@ private Set<Map.Entry<K, V>> entrySet;@b@@b@ public ConcurrentReferenceHashMap()@b@ {@b@ this(16, 0.75F, 16, DEFAULT_REFERENCE_TYPE);@b@ }@b@@b@ public ConcurrentReferenceHashMap(int initialCapacity)@b@ {@b@ this(initialCapacity, 0.75F, 16, DEFAULT_REFERENCE_TYPE);@b@ }@b@@b@ public ConcurrentReferenceHashMap(int initialCapacity, float loadFactor)@b@ {@b@ this(initialCapacity, loadFactor, 16, DEFAULT_REFERENCE_TYPE);@b@ }@b@@b@ public ConcurrentReferenceHashMap(int initialCapacity, int concurrencyLevel)@b@ {@b@ this(initialCapacity, 0.75F, concurrencyLevel, DEFAULT_REFERENCE_TYPE);@b@ }@b@@b@ public ConcurrentReferenceHashMap(int initialCapacity, ReferenceType referenceType)@b@ {@b@ this(initialCapacity, 0.75F, 16, referenceType);@b@ }@b@@b@ public ConcurrentReferenceHashMap(int initialCapacity, float loadFactor, int concurrencyLevel)@b@ {@b@ this(initialCapacity, loadFactor, concurrencyLevel, DEFAULT_REFERENCE_TYPE);@b@ }@b@@b@ public ConcurrentReferenceHashMap(int initialCapacity, float loadFactor, int concurrencyLevel, ReferenceType referenceType)@b@ {@b@ Assert.isTrue(initialCapacity >= 0, "Initial capacity must not be negative");@b@ Assert.isTrue(loadFactor > 0.0F, "Load factor must be positive");@b@ Assert.isTrue(concurrencyLevel > 0, "Concurrency level must be positive");@b@ Assert.notNull(referenceType, "Reference type must not be null");@b@ this.loadFactor = loadFactor;@b@ this.shift = calculateShift(concurrencyLevel, 65536);@b@ int size = 1 << this.shift;@b@ this.referenceType = referenceType;@b@ int roundedUpSegmentCapacity = (int)((initialCapacity + size - 1L) / size);@b@ this.segments = ((Segment[])(Segment[])Array.newInstance(Segment.class, size));@b@ for (int i = 0; i < this.segments.length; ++i)@b@ this.segments[i] = new Segment(this, roundedUpSegmentCapacity);@b@ }@b@@b@ protected final float getLoadFactor()@b@ {@b@ return this.loadFactor;@b@ }@b@@b@ protected final int getSegmentsSize() {@b@ return this.segments.length;@b@ }@b@@b@ protected final ConcurrentReferenceHashMap<K, V>.Segment getSegment(int index) {@b@ return this.segments[index];@b@ }@b@@b@ protected ConcurrentReferenceHashMap<K, V>.ReferenceManager createReferenceManager()@b@ {@b@ return new ReferenceManager(this);@b@ }@b@@b@ protected int getHash(Object o)@b@ {@b@ int hash = (o == null) ? 0 : o.hashCode();@b@ hash += (hash << 15 ^ 0xFFFFCD7D);@b@ hash ^= hash >>> 10;@b@ hash += (hash << 3);@b@ hash ^= hash >>> 6;@b@ hash += (hash << 2) + (hash << 14);@b@ hash ^= hash >>> 16;@b@ return hash;@b@ }@b@@b@ public V get(Object key)@b@ {@b@ Reference reference = getReference(key, Restructure.WHEN_NECESSARY);@b@ Entry entry = (reference != null) ? reference.get() : null;@b@ return ((entry != null) ? entry.getValue() : null);@b@ }@b@@b@ public boolean containsKey(Object key)@b@ {@b@ Reference reference = getReference(key, Restructure.WHEN_NECESSARY);@b@ Entry entry = (reference != null) ? reference.get() : null;@b@ return ((entry != null) && (ObjectUtils.nullSafeEquals(entry.getKey(), key)));@b@ }@b@@b@ protected final Reference<K, V> getReference(Object key, Restructure restructure)@b@ {@b@ int hash = getHash(key);@b@ return getSegmentForHash(hash).getReference(key, hash, restructure);@b@ }@b@@b@ public V put(K key, V value)@b@ {@b@ return put(key, value, true);@b@ }@b@@b@ public V putIfAbsent(K key, V value)@b@ {@b@ return put(key, value, false);@b@ }@b@@b@ private V put(K key, V value, boolean overwriteExisting) {@b@ return doTask(key, new Task(this, new TaskOption[] { TaskOption.RESTRUCTURE_BEFORE, TaskOption.RESIZE }, overwriteExisting, value)@b@ {@b@ protected V execute(, ConcurrentReferenceHashMap.Entry<K, V> entry, ConcurrentReferenceHashMap<K, V>.Entries entries) {@b@ if (entry != null) {@b@ Object previousValue = entry.getValue();@b@ if (this.val$overwriteExisting)@b@ entry.setValue(this.val$value);@b@@b@ return previousValue;@b@ }@b@ entries.add(this.val$value);@b@ return null;@b@ }@b@ });@b@ }@b@@b@ public V remove(Object key)@b@ {@b@ return doTask(key, new Task(this, new TaskOption[] { TaskOption.RESTRUCTURE_AFTER, TaskOption.SKIP_IF_EMPTY })@b@ {@b@ protected V execute(, ConcurrentReferenceHashMap.Entry<K, V> entry) {@b@ if (entry != null) {@b@ reference.release();@b@ return ConcurrentReferenceHashMap.Entry.access$000(entry);@b@ }@b@ return null;@b@ }@b@ });@b@ }@b@@b@ public boolean remove(Object key, Object value)@b@ {@b@ return ((Boolean)doTask(key, new Task(this, new TaskOption[] { TaskOption.RESTRUCTURE_AFTER, TaskOption.SKIP_IF_EMPTY }, value)@b@ {@b@ protected Boolean execute(, ConcurrentReferenceHashMap.Entry<K, V> entry) {@b@ if ((entry != null) && (ObjectUtils.nullSafeEquals(entry.getValue(), this.val$value))) {@b@ reference.release();@b@ return Boolean.valueOf(true);@b@ }@b@ return Boolean.valueOf(false);@b@ }@b@ })).booleanValue();@b@ }@b@@b@ public boolean replace(K key, V oldValue, V newValue)@b@ {@b@ return ((Boolean)doTask(key, new Task(this, new TaskOption[] { TaskOption.RESTRUCTURE_BEFORE, TaskOption.SKIP_IF_EMPTY }, oldValue, newValue)@b@ {@b@ protected Boolean execute(, ConcurrentReferenceHashMap.Entry<K, V> entry) {@b@ if ((entry != null) && (ObjectUtils.nullSafeEquals(entry.getValue(), this.val$oldValue))) {@b@ entry.setValue(this.val$newValue);@b@ return Boolean.valueOf(true);@b@ }@b@ return Boolean.valueOf(false);@b@ }@b@ })).booleanValue();@b@ }@b@@b@ public V replace(K key, V value)@b@ {@b@ return doTask(key, new Task(this, new TaskOption[] { TaskOption.RESTRUCTURE_BEFORE, TaskOption.SKIP_IF_EMPTY }, value)@b@ {@b@ protected V execute(, ConcurrentReferenceHashMap.Entry<K, V> entry) {@b@ if (entry != null) {@b@ Object previousValue = entry.getValue();@b@ entry.setValue(this.val$value);@b@ return previousValue;@b@ }@b@ return null;@b@ }@b@ });@b@ }@b@@b@ public void clear()@b@ {@b@ Segment[] arrayOfSegment = this.segments; int i = arrayOfSegment.length; for (int j = 0; j < i; ++j) { Segment segment = arrayOfSegment[j];@b@ segment.clear();@b@ }@b@ }@b@@b@ public void purgeUnreferencedEntries()@b@ {@b@ Segment[] arrayOfSegment = this.segments; int i = arrayOfSegment.length; for (int j = 0; j < i; ++j) { Segment segment = arrayOfSegment[j];@b@ segment.restructureIfNecessary(false);@b@ }@b@ }@b@@b@ public int size()@b@ {@b@ int size = 0;@b@ Segment[] arrayOfSegment = this.segments; int i = arrayOfSegment.length; for (int j = 0; j < i; ++j) { Segment segment = arrayOfSegment[j];@b@ size += segment.getCount();@b@ }@b@ return size;@b@ }@b@@b@ public Set<Map.Entry<K, V>> entrySet()@b@ {@b@ if (this.entrySet == null)@b@ this.entrySet = new EntrySet(this, null);@b@@b@ return this.entrySet;@b@ }@b@@b@ private <T> T doTask(Object key, ConcurrentReferenceHashMap<K, V>.Task<T> task) {@b@ int hash = getHash(key);@b@ return getSegmentForHash(hash).doTask(hash, key, task);@b@ }@b@@b@ private ConcurrentReferenceHashMap<K, V>.Segment getSegmentForHash(int hash) {@b@ return this.segments[(hash >>> 32 - this.shift & this.segments.length - 1)];@b@ }@b@@b@ protected static int calculateShift(int minimumValue, int maximumValue)@b@ {@b@ int shift = 0;@b@ int value = 1;@b@ while ((value < minimumValue) && (value < maximumValue)) {@b@ value <<= 1;@b@ ++shift;@b@ }@b@ return shift;@b@ }@b@@b@ private static final class WeakEntryReference<K, V> extends WeakReference<ConcurrentReferenceHashMap.Entry<K, V>>@b@ implements ConcurrentReferenceHashMap.Reference<K, V>@b@ {@b@ private final int hash;@b@ private final ConcurrentReferenceHashMap.Reference<K, V> nextReference;@b@@b@ public WeakEntryReference(ConcurrentReferenceHashMap.Entry<K, V> entry, int hash, ConcurrentReferenceHashMap.Reference<K, V> next, ReferenceQueue<ConcurrentReferenceHashMap.Entry<K, V>> queue)@b@ {@b@ super(entry, queue);@b@ this.hash = hash;@b@ this.nextReference = next;@b@ }@b@@b@ public int getHash()@b@ {@b@ return this.hash;@b@ }@b@@b@ public ConcurrentReferenceHashMap.Reference<K, V> getNext()@b@ {@b@ return this.nextReference;@b@ }@b@@b@ public void release()@b@ {@b@ enqueue();@b@ clear();@b@ }@b@ }@b@@b@ private static final class SoftEntryReference<K, V> extends SoftReference<ConcurrentReferenceHashMap.Entry<K, V>>@b@ implements ConcurrentReferenceHashMap.Reference<K, V>@b@ {@b@ private final int hash;@b@ private final ConcurrentReferenceHashMap.Reference<K, V> nextReference;@b@@b@ public SoftEntryReference(ConcurrentReferenceHashMap.Entry<K, V> entry, int hash, ConcurrentReferenceHashMap.Reference<K, V> next, ReferenceQueue<ConcurrentReferenceHashMap.Entry<K, V>> queue)@b@ {@b@ super(entry, queue);@b@ this.hash = hash;@b@ this.nextReference = next;@b@ }@b@@b@ public int getHash()@b@ {@b@ return this.hash;@b@ }@b@@b@ public ConcurrentReferenceHashMap.Reference<K, V> getNext()@b@ {@b@ return this.nextReference;@b@ }@b@@b@ public void release()@b@ {@b@ enqueue();@b@ clear();@b@ }@b@ }@b@@b@ protected class ReferenceManager@b@ {@b@ private final ReferenceQueue<ConcurrentReferenceHashMap.Entry<K, V>> queue;@b@@b@ protected ReferenceManager()@b@ {@b@ this.queue = new ReferenceQueue();@b@ }@b@@b@ public ConcurrentReferenceHashMap.Reference<K, V> createReference(, int hash, ConcurrentReferenceHashMap.Reference<K, V> next)@b@ {@b@ if (ConcurrentReferenceHashMap.access$700(this.this$0) == ConcurrentReferenceHashMap.ReferenceType.WEAK)@b@ return new ConcurrentReferenceHashMap.WeakEntryReference(entry, hash, next, this.queue);@b@@b@ return new ConcurrentReferenceHashMap.SoftEntryReference(entry, hash, next, this.queue);@b@ }@b@@b@ public ConcurrentReferenceHashMap.Reference<K, V> pollForPurge()@b@ {@b@ return ((ConcurrentReferenceHashMap.Reference)this.queue.poll());@b@ }@b@ }@b@@b@ protected static enum Restructure@b@ {@b@ WHEN_NECESSARY, NEVER;@b@ }@b@@b@ private class EntryIterator@b@ implements Iterator<Map.Entry<K, V>>@b@ {@b@ private int segmentIndex;@b@ private int referenceIndex;@b@ private ConcurrentReferenceHashMap.Reference<K, V>[] references;@b@ private ConcurrentReferenceHashMap.Reference<K, V> reference;@b@ private ConcurrentReferenceHashMap.Entry<K, V> next;@b@ private ConcurrentReferenceHashMap.Entry<K, V> last;@b@@b@ public EntryIterator()@b@ {@b@ moveToNextSegment();@b@ }@b@@b@ public boolean hasNext()@b@ {@b@ getNextIfNecessary();@b@ return (this.next != null);@b@ }@b@@b@ public ConcurrentReferenceHashMap.Entry<K, V> next()@b@ {@b@ getNextIfNecessary();@b@ if (this.next == null)@b@ throw new NoSuchElementException();@b@@b@ this.last = this.next;@b@ this.next = null;@b@ return this.last;@b@ }@b@@b@ private void getNextIfNecessary() {@b@ while (this.next == null) {@b@ moveToNextReference();@b@ if (this.reference == null)@b@ return;@b@@b@ this.next = this.reference.get();@b@ }@b@ }@b@@b@ private void moveToNextReference() {@b@ if (this.reference != null)@b@ this.reference = this.reference.getNext(); while (true) {@b@ while (true) {@b@ if ((this.reference != null) || (this.references == null)) return;@b@ if (this.referenceIndex < this.references.length) break;@b@ moveToNextSegment();@b@ this.referenceIndex = 0;@b@ }@b@@b@ this.reference = this.references[this.referenceIndex];@b@ this.referenceIndex += 1;@b@ }@b@ }@b@@b@ private void moveToNextSegment()@b@ {@b@ this.reference = null;@b@ this.references = null;@b@ if (this.segmentIndex < ConcurrentReferenceHashMap.access$600(this.this$0).length) {@b@ this.references = ConcurrentReferenceHashMap.Segment.access$400(ConcurrentReferenceHashMap.access$600(this.this$0)[this.segmentIndex]);@b@ this.segmentIndex += 1;@b@ }@b@ }@b@@b@ public void remove()@b@ {@b@ Assert.state(this.last != null);@b@ this.this$0.remove(this.last.getKey());@b@ }@b@ }@b@@b@ private class EntrySet extends AbstractSet<Map.Entry<K, V>>@b@ {@b@ public Iterator<Map.Entry<K, V>> iterator()@b@ {@b@ return new ConcurrentReferenceHashMap.EntryIterator(this.this$0);@b@ }@b@@b@ public boolean contains()@b@ {@b@ if ((o != null) && (o instanceof Map.Entry)) {@b@ Map.Entry entry = (Map.Entry)o;@b@ ConcurrentReferenceHashMap.Reference reference = this.this$0.getReference(entry.getKey(), ConcurrentReferenceHashMap.Restructure.NEVER);@b@ ConcurrentReferenceHashMap.Entry other = (reference != null) ? reference.get() : null;@b@ if (other != null)@b@ return ObjectUtils.nullSafeEquals(entry.getValue(), other.getValue());@b@ }@b@@b@ return false;@b@ }@b@@b@ public boolean remove()@b@ {@b@ if (o instanceof Map.Entry) {@b@ Map.Entry entry = (Map.Entry)o;@b@ return this.this$0.remove(entry.getKey(), entry.getValue());@b@ }@b@ return false;@b@ }@b@@b@ public int size()@b@ {@b@ return this.this$0.size();@b@ }@b@@b@ public void clear()@b@ {@b@ this.this$0.clear();@b@ }@b@ }@b@@b@ private abstract class Entries@b@ {@b@ public abstract void add();@b@ }@b@@b@ private static enum TaskOption@b@ {@b@ RESTRUCTURE_BEFORE, RESTRUCTURE_AFTER, SKIP_IF_EMPTY, RESIZE;@b@ }@b@@b@ private abstract class Task<T>@b@ {@b@ private final EnumSet<ConcurrentReferenceHashMap.TaskOption> options;@b@@b@ public Task(, ConcurrentReferenceHashMap.TaskOption[] paramArrayOfTaskOption)@b@ {@b@ this.options = ((options.length == 0) ? EnumSet.noneOf(ConcurrentReferenceHashMap.TaskOption.class) : EnumSet.of(options[0], options));@b@ }@b@@b@ public boolean hasOption() {@b@ return this.options.contains(option);@b@ }@b@@b@ protected T execute(, ConcurrentReferenceHashMap.Entry<K, V> entry, ConcurrentReferenceHashMap<K, V>.Entries entries)@b@ {@b@ return execute(reference, entry);@b@ }@b@@b@ protected T execute(, ConcurrentReferenceHashMap.Entry<K, V> entry)@b@ {@b@ return null;@b@ }@b@ }@b@@b@ protected static final class Entry<K, V>@b@ implements Map.Entry<K, V>@b@ {@b@ private final K key;@b@ private volatile V value;@b@@b@ public Entry(K key, V value)@b@ {@b@ this.key = key;@b@ this.value = value;@b@ }@b@@b@ public K getKey()@b@ {@b@ return this.key;@b@ }@b@@b@ public V getValue()@b@ {@b@ return this.value;@b@ }@b@@b@ public V setValue(V value)@b@ {@b@ Object previous = this.value;@b@ this.value = value;@b@ return previous;@b@ }@b@@b@ public String toString()@b@ {@b@ return this.key + "=" + this.value;@b@ }@b@@b@ public final boolean equals(Object other)@b@ {@b@ if (this == other)@b@ return true;@b@@b@ if (!(other instanceof Map.Entry))@b@ return false;@b@@b@ Map.Entry otherEntry = (Map.Entry)other;@b@@b@ return ((ObjectUtils.nullSafeEquals(getKey(), otherEntry.getKey())) && @b@ (ObjectUtils.nullSafeEquals(getValue(), otherEntry.getValue())));@b@ }@b@@b@ public final int hashCode()@b@ {@b@ return (ObjectUtils.nullSafeHashCode(this.key) ^ ObjectUtils.nullSafeHashCode(this.value));@b@ }@b@ }@b@@b@ protected static abstract interface Reference<K, V>@b@ {@b@ public abstract ConcurrentReferenceHashMap.Entry<K, V> get();@b@@b@ public abstract int getHash();@b@@b@ public abstract Reference<K, V> getNext();@b@@b@ public abstract void release();@b@ }@b@@b@ protected final class Segment extends ReentrantLock@b@ {@b@ private final ConcurrentReferenceHashMap<K, V>.ReferenceManager referenceManager;@b@ private final int initialSize;@b@ private volatile ConcurrentReferenceHashMap.Reference<K, V>[] references;@b@ private volatile int count = 0;@b@ private int resizeThreshold;@b@@b@ public Segment(, int initialCapacity)@b@ {@b@ this.referenceManager = this$0.createReferenceManager();@b@ this.initialSize = (1 << ConcurrentReferenceHashMap.calculateShift(initialCapacity, 1073741824));@b@ setReferences(createReferenceArray(this.initialSize));@b@ }@b@@b@ public ConcurrentReferenceHashMap.Reference<K, V> getReference(, int hash, ConcurrentReferenceHashMap.Restructure restructure) {@b@ if (restructure == ConcurrentReferenceHashMap.Restructure.WHEN_NECESSARY)@b@ restructureIfNecessary(false);@b@@b@ if (this.count == 0) {@b@ return null;@b@ }@b@@b@ ConcurrentReferenceHashMap.Reference[] references = this.references;@b@ int index = getIndex(hash, references);@b@ ConcurrentReferenceHashMap.Reference head = references[index];@b@ return findInChain(head, key, hash);@b@ }@b@@b@ public <T> T doTask(, Object key, ConcurrentReferenceHashMap<K, V>.Task<T> task)@b@ {@b@ boolean resize = task.hasOption(ConcurrentReferenceHashMap.TaskOption.RESIZE);@b@ if (task.hasOption(ConcurrentReferenceHashMap.TaskOption.RESTRUCTURE_BEFORE))@b@ restructureIfNecessary(resize);@b@@b@ if ((task.hasOption(ConcurrentReferenceHashMap.TaskOption.SKIP_IF_EMPTY)) && (this.count == 0))@b@ return task.execute(null, null, null);@b@@b@ lock();@b@ try {@b@ int index = getIndex(hash, this.references);@b@ ConcurrentReferenceHashMap.Reference head = this.references[index];@b@ ConcurrentReferenceHashMap.Reference reference = findInChain(head, key, hash);@b@ ConcurrentReferenceHashMap.Entry entry = (reference != null) ? reference.get() : null;@b@ ConcurrentReferenceHashMap.Entries entries = new ConcurrentReferenceHashMap.Entries(this, key, hash, head, index)@b@ {@b@ public void add()@b@ {@b@ ConcurrentReferenceHashMap.Entry newEntry = new ConcurrentReferenceHashMap.Entry(this.val$key, value);@b@ ConcurrentReferenceHashMap.Reference newReference = ConcurrentReferenceHashMap.Segment.access$300(this.this$1).createReference(newEntry, this.val$hash, this.val$head);@b@ ConcurrentReferenceHashMap.Segment.access$400(this.this$1)[this.val$index] = newReference;@b@ ConcurrentReferenceHashMap.Segment.access$508(this.this$1);@b@ }@b@@b@ };@b@ Object localObject1 = task.execute(reference, entry, entries);@b@@b@ return localObject1;@b@ }@b@ finally@b@ {@b@ unlock();@b@ if (task.hasOption(ConcurrentReferenceHashMap.TaskOption.RESTRUCTURE_AFTER))@b@ restructureIfNecessary(resize); } } @b@ // ERROR //@b@ public void clear() { // Byte code:@b@ // 0: aload_0@b@ // 1: getfield 2 org/springframework/util/ConcurrentReferenceHashMap$Segment:count I@b@ // 4: ifne +4 -> 8@b@ // 7: return@b@ // 8: aload_0@b@ // 9: invokevirtual 22 org/springframework/util/ConcurrentReferenceHashMap$Segment:lock ()V@b@ // 12: aload_0@b@ // 13: aload_0@b@ // 14: aload_0@b@ // 15: getfield 10 org/springframework/util/ConcurrentReferenceHashMap$Segment:initialSize I@b@ // 18: invokespecial 11 org/springframework/util/ConcurrentReferenceHashMap$Segment:createReferenceArray (I)[Lorg/springframework/util/ConcurrentReferenceHashMap$Reference;@b@ // 21: invokespecial 12 org/springframework/util/ConcurrentReferenceHashMap$Segment:setReferences ([Lorg/springframework/util/ConcurrentReferenceHashMap$Reference;)V@b@ // 24: aload_0@b@ // 25: iconst_0@b@ // 26: putfield 2 org/springframework/util/ConcurrentReferenceHashMap$Segment:count I@b@ // 29: aload_0@b@ // 30: invokevirtual 26 org/springframework/util/ConcurrentReferenceHashMap$Segment:unlock ()V@b@ // 33: goto +10 -> 43@b@ // 36: astore_1@b@ // 37: aload_0@b@ // 38: invokevirtual 26 org/springframework/util/ConcurrentReferenceHashMap$Segment:unlock ()V@b@ // 41: aload_1@b@ // 42: athrow@b@ // 43: return@b@ //@b@ // Exception table:@b@ // from to target type@b@ // 12 29 36 finally } @b@ protected final void restructureIfNecessary() { boolean needsResize = (this.count > 0) && (this.count >= this.resizeThreshold);@b@ ConcurrentReferenceHashMap.Reference reference = this.referenceManager.pollForPurge();@b@ if ((reference != null) || ((needsResize) && (allowResize))) {@b@ lock();@b@ try {@b@ int countAfterRestructure = this.count;@b@@b@ Set toPurge = Collections.emptySet();@b@ if (reference != null) {@b@ toPurge = new HashSet();@b@ while (reference != null) {@b@ toPurge.add(reference);@b@ reference = this.referenceManager.pollForPurge();@b@ }@b@ }@b@ countAfterRestructure -= toPurge.size();@b@@b@ needsResize = (countAfterRestructure > 0) && (countAfterRestructure >= this.resizeThreshold);@b@ boolean resizing = false;@b@ int restructureSize = this.references.length;@b@ if ((allowResize) && (needsResize) && (restructureSize < 1073741824)) {@b@ restructureSize <<= 1;@b@ resizing = true;@b@ }@b@@b@ ConcurrentReferenceHashMap.Reference[] restructured = (resizing) ? createReferenceArray(restructureSize) : this.references;@b@@b@ for (int i = 0; i < this.references.length; ++i) {@b@ reference = this.references[i];@b@ if (!(resizing))@b@ restructured[i] = null;@b@@b@ while (reference != null) {@b@ if ((!(toPurge.contains(reference))) && (reference.get() != null)) {@b@ int index = getIndex(reference.getHash(), restructured);@b@ restructured[index] = this.referenceManager.createReference(reference@b@ .get(), reference.getHash(), restructured[index]);@b@ }@b@@b@ reference = reference.getNext();@b@ }@b@@b@ }@b@@b@ if (resizing)@b@ setReferences(restructured);@b@@b@ this.count = Math.max(countAfterRestructure, 0);@b@ }@b@ finally {@b@ unlock();@b@ }@b@ }@b@ }@b@@b@ private ConcurrentReferenceHashMap.Reference<K, V> findInChain(, Object key, int hash) {@b@ while (reference != null) {@b@ if (reference.getHash() == hash) {@b@ ConcurrentReferenceHashMap.Entry entry = reference.get();@b@ if (entry != null) {@b@ Object entryKey = entry.getKey();@b@ if ((entryKey == key) || (entryKey.equals(key)))@b@ return reference;@b@ }@b@ }@b@@b@ reference = reference.getNext();@b@ }@b@ return null;@b@ }@b@@b@ private ConcurrentReferenceHashMap.Reference<K, V>[] createReferenceArray()@b@ {@b@ return ((ConcurrentReferenceHashMap.Reference[])(ConcurrentReferenceHashMap.Reference[])Array.newInstance(ConcurrentReferenceHashMap.Reference.class, size));@b@ }@b@@b@ private int getIndex(, ConcurrentReferenceHashMap.Reference<K, V>[] references) {@b@ return (hash & references.length - 1);@b@ }@b@@b@ private void setReferences()@b@ {@b@ this.references = references;@b@ this.resizeThreshold = (int)(references.length * this.this$0.getLoadFactor());@b@ }@b@@b@ public final int getSize()@b@ {@b@ return this.references.length;@b@ }@b@@b@ public final int getCount()@b@ {@b@ return this.count;@b@ }@b@ }@b@@b@ public static enum ReferenceType@b@ {@b@ SOFT, WEAK;@b@ }@b@}