8302899: Executors.newSingleThreadExecutor can use Cleaner to shutdown executor

Reviewed-by: rriggs, martin, dfuchs, bchristi
This commit is contained in:
Alan Bateman 2023-02-25 07:48:57 +00:00
parent 17e3769ed7
commit 2e78d838a5
2 changed files with 128 additions and 86 deletions

View file

@ -36,6 +36,7 @@
package java.util.concurrent;
import static java.lang.ref.Reference.reachabilityFence;
import java.lang.ref.Cleaner.Cleanable;
import java.security.AccessControlContext;
import java.security.AccessControlException;
import java.security.AccessController;
@ -46,6 +47,7 @@ import java.util.Collection;
import java.util.List;
import java.util.concurrent.atomic.AtomicInteger;
import jdk.internal.javac.PreviewFeature;
import jdk.internal.ref.CleanerFactory;
import sun.security.util.SecurityConstants;
/**
@ -173,10 +175,7 @@ public class Executors {
* @return the newly created single-threaded Executor
*/
public static ExecutorService newSingleThreadExecutor() {
return new FinalizableDelegatedExecutorService
(new ThreadPoolExecutor(1, 1,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>()));
return newSingleThreadExecutor(defaultThreadFactory());
}
/**
@ -192,7 +191,7 @@ public class Executors {
* @throws NullPointerException if threadFactory is null
*/
public static ExecutorService newSingleThreadExecutor(ThreadFactory threadFactory) {
return new FinalizableDelegatedExecutorService
return new AutoShutdownDelegatedExecutorService
(new ThreadPoolExecutor(1, 1,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>(),
@ -759,7 +758,11 @@ public class Executors {
e.execute(command);
} finally { reachabilityFence(this); }
}
public void shutdown() { e.shutdown(); }
public void shutdown() {
try {
e.shutdown();
} finally { reachabilityFence(this); }
}
public List<Runnable> shutdownNow() {
try {
return e.shutdownNow();
@ -824,14 +827,28 @@ public class Executors {
}
}
private static class FinalizableDelegatedExecutorService
/**
* A DelegatedExecutorService that uses a Cleaner to shut down the underlying
* ExecutorService when the wrapper becomes phantom reachable.
*/
private static class AutoShutdownDelegatedExecutorService
extends DelegatedExecutorService {
FinalizableDelegatedExecutorService(ExecutorService executor) {
private final Cleanable cleanable;
AutoShutdownDelegatedExecutorService(ExecutorService executor) {
super(executor);
Runnable action = () -> {
if (!executor.isShutdown()) {
PrivilegedAction<Void> pa = () -> { executor.shutdown(); return null; };
@SuppressWarnings("removal")
var ignore = AccessController.doPrivileged(pa);
}
};
cleanable = CleanerFactory.cleaner().register(this, action);
}
@SuppressWarnings("removal")
protected void finalize() {
@Override
public void shutdown() {
super.shutdown();
cleanable.clean(); // unregisters the cleanable
}
}