diff --git a/spring-core/src/main/java/org/springframework/util/ConcurrentReferenceHashMap.java b/spring-core/src/main/java/org/springframework/util/ConcurrentReferenceHashMap.java index 5ca0be0fc2..8cc7602411 100644 --- a/spring-core/src/main/java/org/springframework/util/ConcurrentReferenceHashMap.java +++ b/spring-core/src/main/java/org/springframework/util/ConcurrentReferenceHashMap.java @@ -98,7 +98,7 @@ public class ConcurrentReferenceHashMap extends AbstractMap implemen * Late binding entry set. */ @Nullable - private Set> entrySet; + private volatile Set> entrySet; /** @@ -167,8 +167,8 @@ public class ConcurrentReferenceHashMap extends AbstractMap implemen * @param referenceType the reference type used for entries (soft or weak) */ @SuppressWarnings("unchecked") - public ConcurrentReferenceHashMap(int initialCapacity, float loadFactor, int concurrencyLevel, - ReferenceType referenceType) { + public ConcurrentReferenceHashMap( + int initialCapacity, float loadFactor, int concurrencyLevel, ReferenceType referenceType) { Assert.isTrue(initialCapacity >= 0, "Initial capacity must not be negative"); Assert.isTrue(loadFactor > 0f, "Load factor must be positive"); @@ -215,7 +215,7 @@ public class ConcurrentReferenceHashMap extends AbstractMap implemen * @return the resulting hash code */ protected int getHash(@Nullable Object o) { - int hash = o == null ? 0 : o.hashCode(); + int hash = (o != null ? o.hashCode() : 0); hash += (hash << 15) ^ 0xffffcd7d; hash ^= (hash >>> 10); hash += (hash << 3); @@ -247,8 +247,8 @@ public class ConcurrentReferenceHashMap extends AbstractMap implemen @Nullable private Entry getEntryIfAvailable(@Nullable Object key) { - Reference reference = getReference(key, Restructure.WHEN_NECESSARY); - return (reference != null ? reference.get() : null); + Reference ref = getReference(key, Restructure.WHEN_NECESSARY); + return (ref != null ? ref.get() : null); } /** @@ -281,7 +281,7 @@ public class ConcurrentReferenceHashMap extends AbstractMap implemen return doTask(key, new Task(TaskOption.RESTRUCTURE_BEFORE, TaskOption.RESIZE) { @Override @Nullable - protected V execute(@Nullable Reference reference, @Nullable Entry entry, @Nullable Entries entries) { + protected V execute(@Nullable Reference ref, @Nullable Entry entry, @Nullable Entries entries) { if (entry != null) { V oldValue = entry.getValue(); if (overwriteExisting) { @@ -302,10 +302,10 @@ public class ConcurrentReferenceHashMap extends AbstractMap implemen return doTask(key, new Task(TaskOption.RESTRUCTURE_AFTER, TaskOption.SKIP_IF_EMPTY) { @Override @Nullable - protected V execute(@Nullable Reference reference, @Nullable Entry entry) { + protected V execute(@Nullable Reference ref, @Nullable Entry entry) { if (entry != null) { - if (reference != null) { - reference.release(); + if (ref != null) { + ref.release(); } return entry.value; } @@ -318,10 +318,10 @@ public class ConcurrentReferenceHashMap extends AbstractMap implemen public boolean remove(Object key, final Object value) { Boolean result = doTask(key, new Task(TaskOption.RESTRUCTURE_AFTER, TaskOption.SKIP_IF_EMPTY) { @Override - protected Boolean execute(@Nullable Reference reference, @Nullable Entry entry) { + protected Boolean execute(@Nullable Reference ref, @Nullable Entry entry) { if (entry != null && ObjectUtils.nullSafeEquals(entry.getValue(), value)) { - if (reference != null) { - reference.release(); + if (ref != null) { + ref.release(); } return true; } @@ -335,7 +335,7 @@ public class ConcurrentReferenceHashMap extends AbstractMap implemen public boolean replace(K key, final V oldValue, final V newValue) { Boolean result = doTask(key, new Task(TaskOption.RESTRUCTURE_BEFORE, TaskOption.SKIP_IF_EMPTY) { @Override - protected Boolean execute(@Nullable Reference reference, @Nullable Entry entry) { + protected Boolean execute(@Nullable Reference ref, @Nullable Entry entry) { if (entry != null && ObjectUtils.nullSafeEquals(entry.getValue(), oldValue)) { entry.setValue(newValue); return true; @@ -352,7 +352,7 @@ public class ConcurrentReferenceHashMap extends AbstractMap implemen return doTask(key, new Task(TaskOption.RESTRUCTURE_BEFORE, TaskOption.SKIP_IF_EMPTY) { @Override @Nullable - protected V execute(@Nullable Reference reference, @Nullable Entry entry) { + protected V execute(@Nullable Reference ref, @Nullable Entry entry) { if (entry != null) { V oldValue = entry.getValue(); entry.setValue(value); @@ -393,11 +393,23 @@ public class ConcurrentReferenceHashMap extends AbstractMap implemen } @Override - public Set> entrySet() { - if (this.entrySet == null) { - this.entrySet = new EntrySet(); + public boolean isEmpty() { + for (Segment segment : this.segments) { + if (segment.getCount() > 0) { + return false; + } } - return this.entrySet; + return true; + } + + @Override + public Set> entrySet() { + Set> entrySet = this.entrySet; + if (entrySet == null) { + entrySet = new EntrySet(); + this.entrySet = entrySet; + } + return entrySet; } @Nullable @@ -512,8 +524,8 @@ public class ConcurrentReferenceHashMap extends AbstractMap implemen try { final int index = getIndex(hash, this.references); final Reference head = this.references[index]; - Reference reference = findInChain(head, key, hash); - Entry entry = (reference != null ? reference.get() : null); + Reference ref = findInChain(head, key, hash); + Entry entry = (ref != null ? ref.get() : null); Entries entries = new Entries() { @Override public void add(@Nullable V value) { @@ -524,7 +536,7 @@ public class ConcurrentReferenceHashMap extends AbstractMap implemen Segment.this.count++; } }; - return task.execute(reference, entry, entries); + return task.execute(ref, entry, entries); } finally { unlock(); @@ -559,19 +571,18 @@ public class ConcurrentReferenceHashMap extends AbstractMap implemen * @param allowResize if resizing is permitted */ protected final void restructureIfNecessary(boolean allowResize) { - boolean needsResize = ((this.count > 0) && (this.count >= this.resizeThreshold)); - Reference reference = this.referenceManager.pollForPurge(); - if ((reference != null) || (needsResize && allowResize)) { + boolean needsResize = (this.count > 0 && this.count >= this.resizeThreshold); + Reference ref = this.referenceManager.pollForPurge(); + if (ref != null || (needsResize && allowResize)) { lock(); try { int countAfterRestructure = this.count; - Set> toPurge = Collections.emptySet(); - if (reference != null) { + if (ref != null) { toPurge = new HashSet<>(); - while (reference != null) { - toPurge.add(reference); - reference = this.referenceManager.pollForPurge(); + while (ref != null) { + toPurge.add(ref); + ref = this.referenceManager.pollForPurge(); } } countAfterRestructure -= toPurge.size(); @@ -587,24 +598,25 @@ public class ConcurrentReferenceHashMap extends AbstractMap implemen } // Either create a new table or reuse the existing one - Reference[] restructured = (resizing ? createReferenceArray(restructureSize) : this.references); + Reference[] restructured = + (resizing ? createReferenceArray(restructureSize) : this.references); // Restructure for (int i = 0; i < this.references.length; i++) { - reference = this.references[i]; + ref = this.references[i]; if (!resizing) { restructured[i] = null; } - while (reference != null) { - if (!toPurge.contains(reference)) { - Entry entry = reference.get(); + while (ref != null) { + if (!toPurge.contains(ref)) { + Entry entry = ref.get(); if (entry != null) { - int index = getIndex(reference.getHash(), restructured); + int index = getIndex(ref.getHash(), restructured); restructured[index] = this.referenceManager.createReference( - entry, reference.getHash(), restructured[index]); + entry, ref.getHash(), restructured[index]); } } - reference = reference.getNext(); + ref = ref.getNext(); } } @@ -622,8 +634,8 @@ public class ConcurrentReferenceHashMap extends AbstractMap implemen } @Nullable - private Reference findInChain(Reference reference, @Nullable Object key, int hash) { - Reference currRef = reference; + private Reference findInChain(Reference ref, @Nullable Object key, int hash) { + Reference currRef = ref; while (currRef != null) { if (currRef.getHash() == hash) { Entry entry = currRef.get(); @@ -667,7 +679,6 @@ public class ConcurrentReferenceHashMap extends AbstractMap implemen /** * A reference to an {@link Entry} contained in the map. Implementations are usually * wrappers around specific Java reference implementations (e.g., {@link SoftReference}). - * * @param the key type * @param the value type */ @@ -700,7 +711,6 @@ public class ConcurrentReferenceHashMap extends AbstractMap implemen /** * A single map entry. - * * @param the key type * @param the value type */ @@ -780,26 +790,26 @@ public class ConcurrentReferenceHashMap extends AbstractMap implemen /** * Execute the task. - * @param reference the found reference or {@code null} - * @param entry the found entry or {@code null} + * @param ref the found reference (or {@code null}) + * @param entry the found entry (or {@code null}) * @param entries access to the underlying entries * @return the result of the task * @see #execute(Reference, Entry) */ @Nullable - protected T execute(@Nullable Reference reference, @Nullable Entry entry, @Nullable Entries entries) { - return execute(reference, entry); + protected T execute(@Nullable Reference ref, @Nullable Entry entry, @Nullable Entries entries) { + return execute(ref, entry); } /** * Convenience method that can be used for tasks that do not need access to {@link Entries}. - * @param reference the found reference or {@code null} - * @param entry the found entry or {@code null} + * @param ref the found reference (or {@code null}) + * @param entry the found entry (or {@code null}) * @return the result of the task * @see #execute(Reference, Entry, Entries) */ @Nullable - protected T execute(@Nullable Reference reference, @Nullable Entry entry) { + protected T execute(@Nullable Reference ref, @Nullable Entry entry) { return null; } } @@ -840,9 +850,9 @@ public class ConcurrentReferenceHashMap extends AbstractMap implemen @Override public boolean contains(@Nullable Object o) { if (o instanceof Map.Entry) { - Map.Entry entry = (java.util.Map.Entry) o; - Reference reference = ConcurrentReferenceHashMap.this.getReference(entry.getKey(), Restructure.NEVER); - Entry otherEntry = (reference != null ? reference.get() : null); + Map.Entry entry = (Map.Entry) o; + Reference ref = ConcurrentReferenceHashMap.this.getReference(entry.getKey(), Restructure.NEVER); + Entry otherEntry = (ref != null ? ref.get() : null); if (otherEntry != null) { return ObjectUtils.nullSafeEquals(otherEntry.getValue(), otherEntry.getValue()); } @@ -1003,7 +1013,7 @@ public class ConcurrentReferenceHashMap extends AbstractMap implemen /** - * Internal {@link Reference} implementation for {@link SoftReference Reference} implementation for {@link SoftReferences}. + * Internal {@link Reference} implementation for {@link SoftReference SoftReferences}. */ private static final class SoftEntryReference extends SoftReference> implements Reference { @@ -1040,7 +1050,7 @@ public class ConcurrentReferenceHashMap extends AbstractMap implemen /** - * Internal {@link Reference} implementation for {@link WeakReference Reference} implementation for {@link WeakReferences}. + * Internal {@link Reference} implementation for {@link WeakReference WeakReferences}. */ private static final class WeakEntryReference extends WeakReference> implements Reference {