【问题标题】:Waiting for threadpool to complete execution等待线程池完成执行
【发布时间】:2014-03-18 17:38:25
【问题描述】:

我是线程新手。我搜索了许多与我的问题相关的问题,但我无法找到适合我的解决方案。我正在做的是使用 THREAD_POOL_EXECUTOR 使用四个异步任务从四个不同的社交媒体获取数据。 代码如下。

new Fb().executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
new Twitter().executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
...

mAdapter = new MyAdapter(getActivity(),
                (ArrayList<Model>) showList);
mListView.setAdapter(mAdapter);

我希望调用是并行的,以节省获取数据的时间。现在的想法是我希望所有四个线程都完成工作,然后我想根据时间戳显示排序的数据。现在的问题是我的 setAdapter 在四个线程完成获取数据之前被调用,因为适配器是在 UI 线程上设置的。我想要一种机制来阻止 UI 线程,直到所有四个线程都完成获取数据。

我发现也许我可以使用 ExecutorService 的 shutdown() 和 awaitTermination() 方法。无论如何,如果有人可以帮助我,那就太好了。非常感谢

【问题讨论】:

  • 你是对的。关闭或等待终止。如果要创建许多线程,您还可以扩展线程类并创建自己的线程消息传递并重用相同的线程。也许 java 使用持久线程优化线程创建以避免创建开销,因此使用执行器也可以通过 awaitTermination 来提高效率。
  • 如果我理解正确,AsyncTask 的 onPostExecute(Result) 应该可以解决您的问题。一旦 AsyncTask 完成,它就会在 UI 线程上调用 onPostExecute。您可以记录所有任务是否已完成,一旦完成,您可以在 onPostExecute(Result) 函数的列表视图中设置适配器。
  • 是的,我做了类似的实现。谢谢你的帮助:)

标签: java android multithreading threadpool


【解决方案1】:

我会做的是:

  1. 在您的活动中创建一个空的 ArrayList
  2. 将此arrayList 传递给您的适配器并在您的ListView 上设置适配器。 setAdapter 方法不会影响 listView - 它仍然是空的,因为列表是空的。
  3. 启动 4 个 AsyncTask 并获取数据。在 onPostExecute() 中将此数据添加到 ArrayList 并在适配器上调用 notifyDatasetChanged()。

你永远不应该阻塞 UI 线程,因为它是错误的。当您希望一次显示所有数据时,您可以制作一个简单的计数器,在每个 onPostExecute 中制作 counter++,并仅在计数器为 4 时调用 notifyDatasetChange()。

【讨论】:

  • 这是正确的方法。为任何事情阻塞 UI 线程是一个非常糟糕的主意。充其量,它会让你的应用看起来很丑,因为一切都在锁定。在最坏的情况下,您会收到 ANR 错误。或者,您可以在每次完成时更新适配器并在适配器上调用notifyDatasetChanged(),以便更快地将信息更新给用户。
  • 好的,我很清楚。我不应该考虑阻塞 UI 线程。你们都是对的。我尝试了@Mark 告诉的方式。 Bt 发生的事情是我正在根据创建时间对来自 facebook twitter 等的数据进行排序。所以首先任何线程的数据都会从它的 postExecute() 中设置,然后其他线程完成工作,并在对所有数据进行排序后设置数据。所以新数据会在 notifyDatasetChange() 上添加到 btwn 中,看起来有些模糊。所以我在考虑另一种方式,即 1)仅在所有线程完成执行后打印数据,2)对它们进行排序 3)仅使用最终数据设置适配器一次
  • 你可以照我说的做。设置适配器,在每个 onPostExecute() 中启动所有任务,将数据添加到列表中并生成 counter++。做一个检查counter是否为4的方法,对列表进行排序并使用notifyDatasetChanged(你也可以在这里设置适配器,应该没有更大的区别)。
【解决方案2】:

ExecutorService 调用方法 shutdown()

启动有序关闭,执行之前提交的任务,但不会接受新任务。

http://docs.oracle.com/javase/7/docs/api/java/util/concurrent/ExecutorService.html

【讨论】:

    【解决方案3】:

    如果你真的可以阻止 UI 线程,试试这个:

    new Fb().executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
    new Twitter().executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
    ...
    
    AsyncTask.THREAD_POOL_EXECUTOR.shutdown();
    
    while (!AsyncTask.THREAD_POOL_EXECUTOR.isTerminated()) {}
    
    mAdapter = new MyAdapter(getActivity(),
                    (ArrayList<Model>) showList);
    mListView.setAdapter(mAdapter);
    

    但在大多数情况下,阻塞 UI 线程并不是一个好主意。

    【讨论】:

    • 好的,谢谢你的想法。我会试试你的代码 :) 是的,我也同意阻止 UI 线程不是一个好主意。无论如何,我感谢你的支持
    • AsyncTask.THREAD_POOL_EXECUTOR 不包含方法 shutdown 和 isTerminated。它们来自 ExecutorService。
    • 哎呀,我假设 AsyncTask.THREAD_POOL_EXECUTOR 是一个 ExecutorService。虽然上面的代码不一定有效,但您也许可以创建自己的 ExecutorService 来做类似的事情。不过,您似乎已经接受了答案。
    【解决方案4】:

    我可以成功地处理问题,而无需将 deeo 引入线程。我使用了在每个线程执行后使布尔值为真的简单概念。在 UI 线程中,我检查了无限时间,即

    while(true)
    {
        if(flag1 && flag2 && flag3 && flag4)
        {
           //set the adapter and make the flags false 
           break;
        }
    
    }
    

    不要忘记将 falgs 设置为 false,否则执行将无限期进行。

    【讨论】:

      猜你喜欢
      • 2015-08-29
      • 2010-10-16
      • 1970-01-01
      • 1970-01-01
      • 2011-06-02
      • 2012-07-07
      • 1970-01-01
      • 2014-05-10
      相关资源
      最近更新 更多