首页
学习
活动
专区
工具
TVP
发布
社区首页 >问答首页 >ExecutorService在超出作用域时会被垃圾回收吗?

ExecutorService在超出作用域时会被垃圾回收吗?
EN

Stack Overflow用户
提问于 2014-07-25 18:47:12
回答 2查看 8.8K关注 0票数 22

我之所以问这个问题,是因为我正在创建大量的executor服务,虽然我可能已经在某个地方有一个内存泄漏需要调查,但我认为最近对以下代码的更改实际上加剧了这个问题,因此我试图确认发生了什么:

代码语言:javascript
复制
@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线程,我不确定这是否相关。

问题是:一旦BaseConsumer#accept完成,ExecutorService service是否会超出作用域并被垃圾回收?

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2014-07-25 19:08:17

一旦BaseConsumer.accept()完成,ExecutorService服务是否会超出作用域并被垃圾回收?

是。

实际上,关联的线程池也应该是垃圾收集的……最终会的。

Executors.newSingleThreadExecutor()创建的ExecutorServiceFinalizableDelegatedExecutorService的一个实例。该类具有在包装的ExecutorService对象上调用shutdown()finalize()方法。如果所有未完成的任务都实际终止,服务对象将关闭其线程池。

(AFAIK,未指定此参数。但它是根据源代码在Java6及更高版本中实现的。)

在future.get()周围的try-catch中添加finally { service.shutdown();}是否有助于更快地检索资源?(不一定对服务对象进行垃圾收集)。

是的,确实如此。调用shutdown()会导致在未完成的任务完成后立即释放线程。该过程立即开始,而如果您只是把它留给垃圾收集器,那么直到调用终结器时它才会开始。

现在,如果资源仅仅是“普通”的Java对象,这就无关紧要了。但在本例中,您正在回收的资源是一个Java线程,它具有相关的操作系统资源(例如,本机线程)和一个非平凡的堆外内存块。因此,这样做可能是值得的。

但是如果你想优化这一点,也许你应该创建一个长寿的ExecutorService对象,并在多个“消费者”实例之间共享它。

票数 22
EN

Stack Overflow用户

发布于 2014-07-25 19:45:07

我想让执行发生在一个指定的线程上,这与它更容易被记录有关。在这两种情况下,这段代码都应该可以工作。

您可以更简单/更快地完成此操作

代码语言:javascript
复制
Thread t = Thread.currentThread();
String name = t.getName();
try {
    t.setName("My new thread name for this task");
    // do task
} finally {
    t.setName(name);
}

这样,您就可以使用命名线程,而无需创建新线程。

票数 7
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/24953978

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档