|
35 | 35 | import java.util.concurrent.locks.ReentrantLock;
|
36 | 36 |
|
37 | 37 | import org.springframework.lang.Nullable;
|
| 38 | +import org.springframework.util.ConcurrentReferenceHashMap.Reference; |
| 39 | +import org.springframework.util.ConcurrentReferenceHashMap.Restructure; |
38 | 40 |
|
39 | 41 | /**
|
40 | 42 | * A {@link ConcurrentHashMap} that uses {@link ReferenceType#SOFT soft} or
|
@@ -232,27 +234,24 @@ protected int getHash(@Nullable Object o) {
|
232 | 234 | @Override
|
233 | 235 | @Nullable
|
234 | 236 | public V get(@Nullable Object key) {
|
235 |
| - Entry<K, V> entry = getEntryIfAvailable(key); |
| 237 | + Reference<K, V> ref = getReference(key, Restructure.WHEN_NECESSARY); |
| 238 | + Entry<K, V> entry = (ref != null ? ref.get() : null); |
236 | 239 | return (entry != null ? entry.getValue() : null);
|
237 | 240 | }
|
238 | 241 |
|
239 | 242 | @Override
|
240 | 243 | @Nullable
|
241 | 244 | public V getOrDefault(@Nullable Object key, @Nullable V defaultValue) {
|
242 |
| - Entry<K, V> entry = getEntryIfAvailable(key); |
| 245 | + Reference<K, V> ref = getReference(key, Restructure.WHEN_NECESSARY); |
| 246 | + Entry<K, V> entry = (ref != null ? ref.get() : null); |
243 | 247 | return (entry != null ? entry.getValue() : defaultValue);
|
244 | 248 | }
|
245 | 249 |
|
246 | 250 | @Override
|
247 | 251 | public boolean containsKey(@Nullable Object key) {
|
248 |
| - Entry<K, V> entry = getEntryIfAvailable(key); |
249 |
| - return (entry != null && ObjectUtils.nullSafeEquals(entry.getKey(), key)); |
250 |
| - } |
251 |
| - |
252 |
| - @Nullable |
253 |
| - private Entry<K, V> getEntryIfAvailable(@Nullable Object key) { |
254 | 252 | Reference<K, V> ref = getReference(key, Restructure.WHEN_NECESSARY);
|
255 |
| - return (ref != null ? ref.get() : null); |
| 253 | + Entry<K, V> entry = (ref != null ? ref.get() : null); |
| 254 | + return (entry != null && ObjectUtils.nullSafeEquals(entry.getKey(), key)); |
256 | 255 | }
|
257 | 256 |
|
258 | 257 | /**
|
@@ -573,65 +572,70 @@ public void clear() {
|
573 | 572 | */
|
574 | 573 | protected final void restructureIfNecessary(boolean allowResize) {
|
575 | 574 | int currCount = this.count.get();
|
576 |
| - boolean needsResize = (currCount > 0 && currCount >= this.resizeThreshold); |
| 575 | + boolean needsResize = allowResize && (currCount > 0 && currCount >= this.resizeThreshold); |
577 | 576 | Reference<K, V> ref = this.referenceManager.pollForPurge();
|
578 |
| - if (ref != null || (needsResize && allowResize)) { |
579 |
| - lock(); |
580 |
| - try { |
581 |
| - int countAfterRestructure = this.count.get(); |
582 |
| - Set<Reference<K, V>> toPurge = Collections.emptySet(); |
583 |
| - if (ref != null) { |
584 |
| - toPurge = new HashSet<>(); |
585 |
| - while (ref != null) { |
586 |
| - toPurge.add(ref); |
587 |
| - ref = this.referenceManager.pollForPurge(); |
588 |
| - } |
589 |
| - } |
590 |
| - countAfterRestructure -= toPurge.size(); |
591 |
| - |
592 |
| - // Recalculate taking into account count inside lock and items that |
593 |
| - // will be purged |
594 |
| - needsResize = (countAfterRestructure > 0 && countAfterRestructure >= this.resizeThreshold); |
595 |
| - boolean resizing = false; |
596 |
| - int restructureSize = this.references.length; |
597 |
| - if (allowResize && needsResize && restructureSize < MAXIMUM_SEGMENT_SIZE) { |
598 |
| - restructureSize <<= 1; |
599 |
| - resizing = true; |
| 577 | + if (ref != null || (needsResize)) { |
| 578 | + restructure(allowResize, ref); |
| 579 | + } |
| 580 | + } |
| 581 | + |
| 582 | + private void restructure(boolean allowResize, Reference<K, V> ref) { |
| 583 | + boolean needsResize; |
| 584 | + lock(); |
| 585 | + try { |
| 586 | + int countAfterRestructure = this.count.get(); |
| 587 | + Set<Reference<K, V>> toPurge = Collections.emptySet(); |
| 588 | + if (ref != null) { |
| 589 | + toPurge = new HashSet<>(); |
| 590 | + while (ref != null) { |
| 591 | + toPurge.add(ref); |
| 592 | + ref = this.referenceManager.pollForPurge(); |
600 | 593 | }
|
| 594 | + } |
| 595 | + countAfterRestructure -= toPurge.size(); |
| 596 | + |
| 597 | + // Recalculate taking into account count inside lock and items that |
| 598 | + // will be purged |
| 599 | + needsResize = (countAfterRestructure > 0 && countAfterRestructure >= this.resizeThreshold); |
| 600 | + boolean resizing = false; |
| 601 | + int restructureSize = this.references.length; |
| 602 | + if (allowResize && needsResize && restructureSize < MAXIMUM_SEGMENT_SIZE) { |
| 603 | + restructureSize <<= 1; |
| 604 | + resizing = true; |
| 605 | + } |
601 | 606 |
|
602 |
| - // Either create a new table or reuse the existing one |
603 |
| - Reference<K, V>[] restructured = |
604 |
| - (resizing ? createReferenceArray(restructureSize) : this.references); |
| 607 | + // Either create a new table or reuse the existing one |
| 608 | + Reference<K, V>[] restructured = |
| 609 | + (resizing ? createReferenceArray(restructureSize) : this.references); |
605 | 610 |
|
606 |
| - // Restructure |
607 |
| - for (int i = 0; i < this.references.length; i++) { |
608 |
| - ref = this.references[i]; |
609 |
| - if (!resizing) { |
610 |
| - restructured[i] = null; |
611 |
| - } |
612 |
| - while (ref != null) { |
613 |
| - if (!toPurge.contains(ref)) { |
614 |
| - Entry<K, V> entry = ref.get(); |
615 |
| - if (entry != null) { |
616 |
| - int index = getIndex(ref.getHash(), restructured); |
617 |
| - restructured[index] = this.referenceManager.createReference( |
618 |
| - entry, ref.getHash(), restructured[index]); |
619 |
| - } |
| 611 | + // Restructure |
| 612 | + for (int i = 0; i < this.references.length; i++) { |
| 613 | + ref = this.references[i]; |
| 614 | + if (!resizing) { |
| 615 | + restructured[i] = null; |
| 616 | + } |
| 617 | + while (ref != null) { |
| 618 | + if (!toPurge.contains(ref)) { |
| 619 | + Entry<K, V> entry = ref.get(); |
| 620 | + if (entry != null) { |
| 621 | + int index = getIndex(ref.getHash(), restructured); |
| 622 | + restructured[index] = this.referenceManager.createReference( |
| 623 | + entry, ref.getHash(), restructured[index]); |
620 | 624 | }
|
621 |
| - ref = ref.getNext(); |
622 | 625 | }
|
| 626 | + ref = ref.getNext(); |
623 | 627 | }
|
624 |
| - |
625 |
| - // Replace volatile members |
626 |
| - if (resizing) { |
627 |
| - this.references = restructured; |
628 |
| - this.resizeThreshold = (int) (this.references.length * getLoadFactor()); |
629 |
| - } |
630 |
| - this.count.set(Math.max(countAfterRestructure, 0)); |
631 | 628 | }
|
632 |
| - finally { |
633 |
| - unlock(); |
| 629 | + |
| 630 | + // Replace volatile members |
| 631 | + if (resizing) { |
| 632 | + this.references = restructured; |
| 633 | + this.resizeThreshold = (int) (this.references.length * getLoadFactor()); |
634 | 634 | }
|
| 635 | + this.count.set(Math.max(countAfterRestructure, 0)); |
| 636 | + } |
| 637 | + finally { |
| 638 | + unlock(); |
635 | 639 | }
|
636 | 640 | }
|
637 | 641 |
|
|
0 commit comments