mirror of
https://gitflic.ru/project/openide/openide.git
synced 2025-12-15 02:59:33 +07:00
IJPL-568 ConcurrentRefValueHashMap.putIfAbsent does not get rid of obsolete references when the insertion succeeds from the first try
GitOrigin-RevId: 377c170b64fc92f732d33ce811601b6d20ea1a73
This commit is contained in:
committed by
intellij-monorepo-bot
parent
9a6807daab
commit
0fe1ce6791
@@ -17,6 +17,8 @@ import org.junit.Rule;
|
|||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
import org.junit.rules.TestRule;
|
import org.junit.rules.TestRule;
|
||||||
|
|
||||||
|
import java.lang.ref.Reference;
|
||||||
|
import java.lang.ref.SoftReference;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
import java.util.concurrent.ConcurrentMap;
|
import java.util.concurrent.ConcurrentMap;
|
||||||
|
|
||||||
@@ -179,6 +181,24 @@ public class ContainerUtilCollectionsTest extends Assert {
|
|||||||
checkValueTossedEventually(map);
|
checkValueTossedEventually(map);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test(timeout = TIMEOUT)
|
||||||
|
public void testValueTossedEvenInCaseOfSuccessfulPutIfAbsentInConcurrentSoftValueMap() {
|
||||||
|
ConcurrentSoftValueHashMap<Object, Object> map = new ConcurrentSoftValueHashMap<>();
|
||||||
|
Object value = new Object();
|
||||||
|
Reference<Object> ref = new SoftReference<>(value);
|
||||||
|
map.put(1, value);
|
||||||
|
assertEquals(1, map.size());
|
||||||
|
value = null;
|
||||||
|
|
||||||
|
do {
|
||||||
|
GCUtil.tryGcSoftlyReachableObjects();
|
||||||
|
}
|
||||||
|
while (ref.get()!=null);
|
||||||
|
Object old = map.putIfAbsent(2, new Object());
|
||||||
|
assertNull(old);
|
||||||
|
assertFalse(map.processQueue());
|
||||||
|
}
|
||||||
|
|
||||||
@SuppressWarnings("ConstantValue") // Map contract is tested, not implied here
|
@SuppressWarnings("ConstantValue") // Map contract is tested, not implied here
|
||||||
private void checkClearsEventuallyAfterGCPressure(Map<Object, Object> map, @NotNull Runnable putKey) {
|
private void checkClearsEventuallyAfterGCPressure(Map<Object, Object> map, @NotNull Runnable putKey) {
|
||||||
assertTrue(map.isEmpty());
|
assertTrue(map.isEmpty());
|
||||||
|
|||||||
@@ -61,9 +61,9 @@ abstract class ConcurrentRefValueHashMap<K, V> implements ConcurrentMap<K, V> {
|
|||||||
public V putIfAbsent(@NotNull K key, @NotNull V value) {
|
public V putIfAbsent(@NotNull K key, @NotNull V value) {
|
||||||
ValueReference<K, V> newRef = createValueReference(key, value);
|
ValueReference<K, V> newRef = createValueReference(key, value);
|
||||||
while (true) {
|
while (true) {
|
||||||
|
processQueue();
|
||||||
ValueReference<K, V> oldRef = myMap.putIfAbsent(key, newRef);
|
ValueReference<K, V> oldRef = myMap.putIfAbsent(key, newRef);
|
||||||
if (oldRef == null) return null;
|
if (oldRef == null) return null;
|
||||||
processQueue();
|
|
||||||
V oldVal = oldRef.get();
|
V oldVal = oldRef.get();
|
||||||
if (oldVal == null) {
|
if (oldVal == null) {
|
||||||
if (myMap.replace(key, oldRef, newRef)) return null;
|
if (myMap.replace(key, oldRef, newRef)) return null;
|
||||||
|
|||||||
Reference in New Issue
Block a user