使用并行线程进行不同的网络操作

时间:2014-07-26 04:58:23

标签: java android multithreading android-asynctask parallel-processing

我正在编写一个应该首先逐个运行2个方法的应用程序,每个方法需要2秒才能获得第一个tokenId,之后运行3-5个调用不同的Web服务来获取数据。每次拨打web service都需要5秒钟,因此我不想在逐个运行时等待20秒。

获取连接然后获取令牌:

获得结果后,

connect()运行getToken ()

之后我需要显示我从3-5 web services获得的数据,所以我认为这样做可以节省一些时间。我不想等到每个完成然后运行下一个,所以我可能需要使用3-5个并行Threads,然后每个Thread将数据保存到可共享的地方毕竟在UI上完成了显示数据。

有些问题:

1-实施connect()以及getToken() AsyncTask我应该为connect()运行onPostExecute(),然后在AsyncTask开始新的getToken() connect()的结果来自Theards

2-因为我在每个网络服务中的所有工作都在发送数据并等待它的来临 - 当每个网站无法调用不同的web service时创建3-4 {{1}}是正确的。获得结果 - 之后将其保存到全局位置并且仅在完成后才显示它?如何实现这样的事情?

2 个答案:

答案 0 :(得分:2)

是的,您可以运行多个异步任务,最多128个,这是在android中运行同步异步任务的线程池容量。阅读下面的描述或从github下载示例。

AsyncTask使用线程池模式来运行doInBackground()中的东西。问题最初(在早期的Android OS版本中)池大小只有1,这意味着没有对一堆AsyncTasks进行并行计算。但后来他们修复了这个问题,现在大小为5,所以最多可以同时运行5个AsyncTasks。不幸的是,我不记得他们究竟改变了什么版本。

以下是当前(2012-01-27)AP​​I对此的说法:

首次引入时,AsyncTasks在单个后台线程上串行执行。从DONUT开始,这被改为一个线程池,允许多个任务并行运行。在HONEYCOMB之后,计划将其更改回单个线程以避免由并行执行引起的常见应用程序错误。如果您真的想要并行执行,可以使用THREAD_POOL_EXECUTOR使用此方法的executeOnExecutor(Executor,Params ...)版本;但是,请在那里查看有关其使用的警告。

DONUT是Android 1.6,HONEYCOMB是Android 3.0。

事实证明,对于API来说,一个线程池允许多个任务并行运行"使用(从1.6开始到3.0结束)同时运行的AsyncTasks的数量取决于已经执行了多少任务,但还没有完成他们的doInBackground()。

这是我在2.2上测试/确认的。假设您有一个自定义的AsyncTask,只需在doInBackground()中休眠一秒。 AsyncTasks在内部使用固定大小的队列来存储延迟的任务。队列大小默认为10。如果你连续启动15个自定义任务,那么前5个将进入他们的doInBackground(),但其余的将在队列中等待一个免费的工作线程。只要前5个中的任何一个完成,从而释放工作线程,队列中的任务就会开始执行。因此,在这种情况下,最多5个任务将同时运行。但是,如果您连续启动16个自定义任务,那么前5个将进入他们的doInBackground(),其余10个将进入队列,但是对于第16个,将创建一个新的工作线程,以便它开始执行immediatelly。因此,在这种情况下,最多可以同时运行6个任务。

可以同时运行多少任务的数量有限。由于AsyncTask使用具有有限最大工作线程数的线程池执行程序(128)并且延迟任务队列具有固定大小10,因此如果您尝试执行超过138个自定义任务,则应用程序将因java.util.concurrent.RejectedExecutionException而崩溃

从3.0开始,API允许通过AsyncTask.executeOnExecutor(Executor exec,Params ... params)方法使用自定义线程池执行程序。例如,如果默认值10不是您需要的,则允许配置延迟任务队列的大小。

这是一个简单的测试应用程序,可以执行大量任务,串行与并行执行:https://github.com/vitkhudenko/test_asynctas

答案 1 :(得分:0)

您可以探索使用CountDownlatch和未来的可能性。获得令牌后,使用实现Callable的worker类实例化线程。并且在每个进程countDown和一旦完成之后调用等待锁定器以便能够等待所有踏板完成。完成后,您可以在Future上调用get方法,这将允许您访问结果,而不是将结果存储在common / golbal变量中。