mirror of
https://github.com/openjdk/jdk.git
synced 2025-08-27 14:54:52 +02:00
8302899: Executors.newSingleThreadExecutor can use Cleaner to shutdown executor
Reviewed-by: rriggs, martin, dfuchs, bchristi
This commit is contained in:
parent
17e3769ed7
commit
2e78d838a5
2 changed files with 128 additions and 86 deletions
|
@ -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
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue