diff --git a/src/java.base/share/classes/jdk/internal/util/ReferencedKeyMap.java b/src/java.base/share/classes/jdk/internal/util/ReferencedKeyMap.java index f102e3c94e1..be392c3ae2d 100644 --- a/src/java.base/share/classes/jdk/internal/util/ReferencedKeyMap.java +++ b/src/java.base/share/classes/jdk/internal/util/ReferencedKeyMap.java @@ -439,4 +439,30 @@ public final class ReferencedKeyMap implements Map { return interned; } + + /** + * Attempt to add key to map if absent. + * + * @param setMap {@link ReferencedKeyMap} where interning takes place + * @param key key to add + * + * @param type of key + * + * @return true if the key was added + */ + static boolean internAddKey(ReferencedKeyMap> setMap, T key) { + ReferenceKey entryKey = setMap.entryKey(key); + setMap.removeStaleReferences(); + ReferenceKey existing = setMap.map.putIfAbsent(entryKey, entryKey); + if (existing == null) { + return true; + } else { + // If {@code putIfAbsent} returns non-null then was actually a + // {@code replace} and older key was used. In that case the new + // key was not used and the reference marked stale. + entryKey.unused(); + return false; + } + } + } diff --git a/src/java.base/share/classes/jdk/internal/util/ReferencedKeySet.java b/src/java.base/share/classes/jdk/internal/util/ReferencedKeySet.java index 807eea87dfe..21b940439e0 100644 --- a/src/java.base/share/classes/jdk/internal/util/ReferencedKeySet.java +++ b/src/java.base/share/classes/jdk/internal/util/ReferencedKeySet.java @@ -148,7 +148,7 @@ public final class ReferencedKeySet extends AbstractSet { @Override public boolean add(T e) { - return intern(e) == null; + return ReferencedKeyMap.internAddKey(map, e); } @Override diff --git a/test/jdk/jdk/internal/util/ReferencedKeyTest.java b/test/jdk/jdk/internal/util/ReferencedKeyTest.java index c5edaedd2e2..75690fa6e25 100644 --- a/test/jdk/jdk/internal/util/ReferencedKeyTest.java +++ b/test/jdk/jdk/internal/util/ReferencedKeyTest.java @@ -127,6 +127,12 @@ public class ReferencedKeyTest { assertTrue(element1 == intern1, "intern failed"); // must be same object assertTrue(intern2 != null, "intern failed"); assertTrue(element3 == intern3, "intern failed"); + + Long value1 = Long.valueOf(BASE_KEY + 999); + Long value2 = Long.valueOf(BASE_KEY + 999); + assertTrue(set.add(value1), "key not added"); + assertTrue(!set.add(value1), "key added after second attempt"); + assertTrue(!set.add(value2), "key should not have been added"); } // Borrowed from jdk.test.lib.util.ForceGC but couldn't use from java.base/jdk.internal.util