异步任务线程永远不会死亡

112
我正在使用AsyncTask来响应用户按下按钮获取数据。 这个方法可以使界面保持响应并且同时获取数据。但是当我在Eclipse调试器中查看时,我发现每次创建新的AsyncTask时(这经常发生,因为它们只能使用一次),都会创建一个新线程但从未终止。
结果是有大量的AsyncTask线程闲置。 我不确定这在实践中是否是问题,但我真的想摆脱这些额外的线程。
如何终止这些线程?

“永不终止”是什么意思?任务是否从未结束其doInBackground方法,还是您只在分配跟踪器中看到asynctask对象? - Francesco Laurita
7
doInBackground方法已经执行完成,但线程仍然会出现在调试窗口中。例如:Thread [<23> AsyncTask #4](Running) - Computerish
4个回答

202

AsyncTask 管理一个由 ThreadPoolExecutor 创建的线程池,该线程池将拥有 5 至 128 个线程。如果超过 5 个线程,则这些额外的线程最多会在 10 秒内被移除。(注意:这些数字是针对当前可见的开源代码,并且随着 Android 版本的发布而变化)。

请不要干扰 AsyncTask 的线程。


7
为了节省后续请求的时间,可能会分叉线程。 - CommonsWare
@CommonsWare 我有一个服务,在其中运行一个 AsyncTask 来执行一些操作,当小部件按钮被按下时,服务开始运行,当任务完成后,它必须立即停止服务,但有时 AsyncTask 不会停止,您能告诉我如何停止它吗? - Hunt
那么,如果我使用AsyncTask下载某些东西(歌曲、视频等),而最终用户渴望下载并认为它是一个类似于Torrent的应用程序,并且经理责怪我该怎么办? - Ahmad Dwaik 'Warlock'
1
@SreekanthKarumanaghat:通常情况下,对于需要很长时间才能完成的任务使用AsyncTask是一个不好的主意。但是,我的评论是关于额外线程何时消失的问题。因此,当你的6个任务中的一个结束时,它的线程将在池中保留10秒钟,之后该线程将被终止。 - CommonsWare
1
@SreekanthKarumanaghat:“我的问题是同时运行20个(比如)AsyncTask是否有限制?”——今天大量使用AsyncTask并不是一个好的计划。拥有运行10秒以上的20个或更多任务可能会导致代码审查失败。如果您快速创建20个任务,只有一部分会立即运行,其余部分将被排队等待后续执行。可以同时运行多少个任务取决于CPU的核心数。据我所知,当前算法是2N+1个并行线程,其中N是核心数。 - CommonsWare
显示剩余5条评论

24

除了CommonsWare的回答:

目前我正在使用Android 2.2,我的应用程序每次只使用一个AsyncTask,但我每隔x分钟就会创建一个新的。一开始,新的AsyncTask线程开始出现(为新的AsyncTask创建一个新线程),但在5个线程后(如CommonsWare所述),它们只会保持在调试窗口中,并在需要新的AsyncTask线程时被重复使用。它们会一直保留在那里,直到调试器断开连接。


2
是的,确认无超过5个AsyncTasks。 - Seraphim's

4

我也遇到了同样的问题。在我关闭Activity后,线程仍然卡在那里,希望应用程序能完全关闭。通过使用单线程执行器部分解决了这个问题:

    myActiveTask.executeOnExecutor(Executors.newSingleThreadExecutor());

完成工作后,该线程将会消失。

这个答案使AsyncTask在运行后消失了,也许这不是"谷歌的方法",但它完成了工作。谢谢。 - Henrique de Sousa
这解决了我关于在单个线程上运行异步任务的具体问题。 - Lawrence Gimenez

0
使用 ThreadPoolExecutor
BlockingQueue workQueue= new LinkedBlockingQueue<Runnable>(100); // Work pool size
ThreadPoolExecutor executor = new ThreadPoolExecutor(
            Runtime.getRuntime().availableProcessors(),       // Initial pool size
            Runtime.getRuntime().availableProcessors(),       // Max pool size
            1, // KEEP_ALIVE_TIME
            TimeUnit.SECONDS, //  KEEP_ALIVE_TIME_UNIT
            workQueue);

使用 execute() 方法发布您的Runnable任务。

void execute (Runnable command)

在将来的某个时间执行给定的任务。该任务可以在新线程或现有池线程中执行。
关于您的第二个查询:
如何终止这些线程?
一旦您完成了所有与ThreadPoolExecutor的工作,请按照下面的帖子中引用的正确方式关闭它: 如何正确关闭java ExecutorService

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接