13

假设我计划在我的整个应用程序中使用一个 executorservice,我将向其发送新的 runnable 或 callable 以执行/提交,并且在我这样做之后我会立即关闭。我只想将我的“任务”扔给 executorservice 并让他处理它们并执行它们并提供资源(他有多少线程可用,如果需要,他可以创建多少线程,然后相应地对这些任务进行排队)。

根据您在 Android 应用程序中使用 ExecutorService 的经验,并考虑到应用程序状态的变化,如果我不想通过这样做不断关闭并重新创建 executorservice:

    executor = Executors.newCachedThreadPool();
    executor.submit(some Runnable);
    executor.shutdown();

,您建议什么时间和什么地点关闭服务,然后再恢复它,这样我可以防止一些泄漏或一些不可预见的后果?

我主要指的是:

1)在后台堆栈中的最后一个活动上通过后退按钮关闭应用程序(应用程序使用许多活动)2)应用程序进入后台(在任何这些活动上)3)应用程序返回到前台(在任何这些活动上)

4

3 回答 3

15

你可以做一项工作。将执行程序创建为守护程序。然后它会在您的应用程序退出时自动结束。您不必显式调用shutdown.

 ExecutorService es = Executors.newSingleThreadExecutor( new ThreadFactory() {
    @Override
    public Thread newThread(Runnable r) {
        Thread t = new Thread(r);
        t.setDaemon(true);
        return t;
    }
});
于 2014-03-05T09:29:11.877 回答
7

我有一个 ExecutorService 的单例实例,它通过 Dagger 的对象图作用于 Android 应用程序实例。因此,实例与 Application 对象本身一样长。由于 Android 的 Application 类不提供 onDestroy() 回调,因此永远不知道何时应在 ExecutorService 上调用 shutdown()。

由于我害怕内存泄漏,我也在研究 ThreadPoolExecutor 并使用它来找出答案。这就是我发现的: Executors.newCachedThreadPool() 使用以下参数创建一个 ThreadPoolExecutor:

ThreadPoolExecutor(0, Integer.MAX_VALUE, 60L, TimeUnit.SECONDS, new SynchronousQueue<Runnable>())

即 corePoolSize 为 0,这意味着至少有 0 个工作线程保持活动状态,因此没有。当 TPE(又名 ExecutorService)执行任务时,它会创建一个工作线程并将其添加到池中。现在,当在 60 秒超时期间没有新任务进入时,(仍然保持活动状态的)工作线程将被终止并从池(缓存)中删除。

对我来说,这意味着不会发生内存泄漏,即使从未在 ExecutorService 上调用 shutdown(),因为曾经存在的所有工作线程都会超时,并且在期间没有新任务进入时将从池中删除超时时间。我想那样的话,池中不会有任何对工作线程的引用,因此 GC 可以清理 TPE 实例。

如果我错了,请随时纠正我。

于 2014-11-20T23:14:02.380 回答
0

尽管这个问题已经发布多年,但最近 Android API 30 已弃用 AsyncTask 并且有人可能会卡在这里。要回答这个问题,除非有任何空闲线程,否则无需关闭单例 ExecutorService。根据Oracle 文档

程序中不再引用且没有剩余线程的池将shutdown自动生成。如果您想确保即使用户忘记调用也能回收未引用的池 shutdown(),那么您必须通过设置适当的保持活动时间、使用零核心线程的下限来安排未使用的线程最终死亡...

对于这种情况,这Executors.newCachedThreadPool()是一个很好的工厂方法。当您的应用程序进程终止时,它将自动关闭。

我的应用程序.java:

public class MyApplication extends Application {
    private static ExecutorService executorService = Executors.newCachedThreadPool();
    ...
    public static Executor getExecutor() {
        return executorService;
    }
}

只需MyApplication.getExecutor()在代码中的任何位置使用。

于 2021-06-08T18:48:44.940 回答