8141596: java/util/concurrent/ScheduledThreadPoolExecutor/GCRetention.java starts failing intermittently
Reviewed-by: martin, psandoz, dholmes
This commit is contained in:
parent
1506580766
commit
908c3c315e
@ -34,12 +34,12 @@
|
|||||||
/*
|
/*
|
||||||
* @test
|
* @test
|
||||||
* @summary Ensure that waiting pool threads don't retain refs to tasks.
|
* @summary Ensure that waiting pool threads don't retain refs to tasks.
|
||||||
* @library /lib/testlibrary/
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import static java.util.concurrent.TimeUnit.MILLISECONDS;
|
import java.lang.ref.ReferenceQueue;
|
||||||
|
|
||||||
import java.lang.ref.WeakReference;
|
import java.lang.ref.WeakReference;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
import java.util.concurrent.Delayed;
|
import java.util.concurrent.Delayed;
|
||||||
import java.util.concurrent.ExecutionException;
|
import java.util.concurrent.ExecutionException;
|
||||||
import java.util.concurrent.Future;
|
import java.util.concurrent.Future;
|
||||||
@ -47,10 +47,8 @@ import java.util.concurrent.RunnableScheduledFuture;
|
|||||||
import java.util.concurrent.ScheduledThreadPoolExecutor;
|
import java.util.concurrent.ScheduledThreadPoolExecutor;
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
import java.util.concurrent.TimeoutException;
|
import java.util.concurrent.TimeoutException;
|
||||||
import jdk.testlibrary.Utils;
|
|
||||||
|
|
||||||
public class GCRetention {
|
public class GCRetention {
|
||||||
static final long LONG_DELAY_MS = Utils.adjustTimeout(10_000);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A custom thread pool with a custom RunnableScheduledFuture, for the
|
* A custom thread pool with a custom RunnableScheduledFuture, for the
|
||||||
@ -80,53 +78,48 @@ public class GCRetention {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int countRefsCleared(WeakReference<?>[] refs) {
|
void removeAll(ReferenceQueue<?> q, int n) throws InterruptedException {
|
||||||
int count = 0;
|
for (int j = n; j--> 0; ) {
|
||||||
for (WeakReference<?> ref : refs)
|
if (q.poll() == null) {
|
||||||
if (ref.get() == null)
|
for (;;) {
|
||||||
count++;
|
System.gc();
|
||||||
return count;
|
if (q.remove(1000) != null)
|
||||||
|
break;
|
||||||
|
System.out.printf(
|
||||||
|
"%d/%d unqueued references remaining%n", j, n);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
check(q.poll() == null);
|
||||||
}
|
}
|
||||||
|
|
||||||
void test(String[] args) throws Throwable {
|
void test(String[] args) throws Throwable {
|
||||||
CustomPool pool = new CustomPool(10);
|
final CustomPool pool = new CustomPool(10);
|
||||||
final int size = 100;
|
final int size = 100;
|
||||||
WeakReference<?>[] refs = new WeakReference<?>[size];
|
final ReferenceQueue<Object> q = new ReferenceQueue<>();
|
||||||
Future<?>[] futures = new Future<?>[size];
|
final List<WeakReference<?>> refs = new ArrayList<>(size);
|
||||||
for (int i = 0; i < size; i++) {
|
final List<Future<?>> futures = new ArrayList<>(size);
|
||||||
final Object x = new Object();
|
|
||||||
refs[i] = new WeakReference<Object>(x);
|
// Schedule custom tasks with strong references.
|
||||||
// Create a Runnable with a strong ref to x.
|
class Task implements Runnable {
|
||||||
Runnable r = new Runnable() {
|
final Object x;
|
||||||
public void run() { System.out.println(x); }
|
Task() { refs.add(new WeakReference<>(x = new Object(), q)); }
|
||||||
};
|
public void run() { System.out.println(x); }
|
||||||
// Schedule a custom task with a strong reference to r.
|
|
||||||
// Later tasks have earlier expiration, to ensure multiple
|
|
||||||
// residents of queue head.
|
|
||||||
futures[i] = pool.schedule(r, size*2-i, TimeUnit.MINUTES);
|
|
||||||
}
|
|
||||||
Thread.sleep(10);
|
|
||||||
for (int i = 0; i < size; i++) {
|
|
||||||
if (futures[i] != null) {
|
|
||||||
futures[i].cancel(false);
|
|
||||||
futures[i] = null;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
// Give tasks added later earlier expiration, to ensure
|
||||||
|
// multiple residents of queue head.
|
||||||
|
for (int i = size; i--> 0; )
|
||||||
|
futures.add(pool.schedule(new Task(), i + 1, TimeUnit.MINUTES));
|
||||||
|
futures.forEach(future -> future.cancel(false));
|
||||||
|
futures.clear();
|
||||||
|
|
||||||
pool.purge();
|
pool.purge();
|
||||||
int cleared = 0;
|
removeAll(q, size);
|
||||||
for (int i = 0;
|
for (WeakReference<?> ref : refs) check(ref.get() == null);
|
||||||
i < 10 && (cleared = countRefsCleared(refs)) < size;
|
|
||||||
i++) {
|
|
||||||
System.gc();
|
|
||||||
System.runFinalization();
|
|
||||||
Thread.sleep(10);
|
|
||||||
}
|
|
||||||
pool.shutdown();
|
pool.shutdown();
|
||||||
pool.awaitTermination(LONG_DELAY_MS, MILLISECONDS);
|
// rely on test harness to handle timeout
|
||||||
if (cleared < size)
|
pool.awaitTermination(1L, TimeUnit.DAYS);
|
||||||
throw new Error(String.format
|
|
||||||
("references to %d/%d tasks retained (\"leaked\")",
|
|
||||||
size - cleared, size));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//--------------------- Infrastructure ---------------------------
|
//--------------------- Infrastructure ---------------------------
|
||||||
|
Loading…
x
Reference in New Issue
Block a user