我问这个问题是因为我正在创建很多执行程序服务,虽然我可能已经在某个地方有内存泄漏需要调查,但我认为最近对以下代码的更改实际上使它变得更糟,因此我是试图确认发生了什么:
@FunctionalInterface
public interface BaseConsumer extends Consumer<Path> {
@Override
default void accept(final Path path) {
String name = path.getFileName().toString();
ExecutorService service = Executors.newSingleThreadExecutor(runnable -> {
Thread thread = new Thread(runnable, "documentId=" + name);
thread.setDaemon(true);
return thread;
});
Future<?> future = service.submit(() -> {
baseAccept(path);
return null;
});
try {
future.get();
} catch (InterruptedException ex) {
Thread.currentThread().interrupt();
} catch (ExecutionException ex) {
throw new RuntimeException(ex);
}
}
void baseAccept(final Path path) throws Exception;
}
然后这个Consumer<Path>
在具有(通常)N=2 个线程的另一个线程池上被调用,我不确定这是否相关。
问题是:ExecutorService service
超出范围并收集一次垃圾BaseConsumer#accept
完成了吗?
最佳答案
Does the ExecutorService service go out of scope and get garbage collected once
BaseConsumer.accept()
has finished?
是的。
的确,关联的线程池也应该被垃圾回收……最终。
由 Executors.newSingleThreadExecutor()
创建的 ExecutorService
是 FinalizableDelegatedExecutorService
的一个实例。该类具有 finalize()
方法,该方法在包装的 ExecutorService
对象上调用 shutdown()
。如果所有未完成的任务实际终止,服务对象将关闭其线程池。
(据我所知,这不是指定的。但它是根据源代码实现的,在 Java 6 之后。)
Does adding a finally { service.shutdown(); } in the try-catch around future.get() help in retrieving resources quicker? (not necessarily garbage collecting the service object).
是的。调用 shutdown()
会导致线程在未完成的任务完成后立即释放。该过程会立即开始,而如果您只是将其留给垃圾收集器处理,则在调用终结器之前它不会开始。
现在,如果资源只是“普通”Java 对象,这就没有关系了。但在这种情况下,您要回收的资源是一个 Java 线程,它具有关联的操作系统资源(例如 native 线程)和一个重要的堆外内存块。所以这样做可能是值得的。
但如果您希望对此进行优化,也许您应该创建一个长期存在的 ExecutorService
对象,并在多个“消费者”实例之间共享它。
关于java - ExecutorService 是否在超出范围时收集垃圾?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/24953978/