【问题标题】:is it safe to use ThreadPoolExecutor inside AsyncTask doInBackground在 AsyncTask doInBackground 中使用 ThreadPoolExecutor 是否安全
【发布时间】:2014-05-29 10:28:28
【问题描述】:

我必须下载一个带有文件列表的 Json,然后并行下载列表中的文件。我想定期更新ProgressDialog,所以我是这样实现的

  • 我创建并显示对话框
  • 我开始AsyncTask

    • onProgressUpdate接收2个整数,当前进度和最大进度,并更新进度条

    • doInBackground

      • 下载json文件并获取要下载的文件列表
      • 创建一个ThreadPoolExecutor (tpe),带有一个LinkedBlockingQueue<Runnable>
      • 为每个文件提交一个可运行文件,使用 Apache 将文件下载到磁盘commons-io FileUtils.copyURLToFile
      • 执行关机
    • 在一段时间内。 tpe.awaitTermination(1, TimeUnit.SECONDS) 定期调用 publishProgress( (int) tpe.getCompletedTaskCount(), tot),更新进度条
    • onPostExecute 隐藏和关闭进度条,并管理文件下载

在 AsynTask 中使用 ThreadPoolExecutor 有什么问题吗? 我正在与一位同事讨论,他声称线程管理中可能存在问题,可能会出现死锁,并且可能会给我们未来的版本带来问题

这是代码

public static void syncFiles(...)
{
    PowerManager pm = (PowerManager) context.getSystemService(Context.POWER_SERVICE);
    sWakelock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, TAG);
    sWakelock.acquire();

    sProgress = new ProgressDialog(context);
    sProgress.setCancelable(false);
    sProgress.setTitle("MyTitle");
    sProgress.setMessage("Sincronizzazione in corso");
    sProgress.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
    sProgress.setIndeterminate(false);
    sProgress.show();

    sCurrentTask = new AsyncTask<Void, Integer, Manifest>()
    {

        @Override
        protected void onCancelled()
        {
            if ((sProgress != null) && sProgress.isShowing())
                sProgress.dismiss();

            if ((sWakelock != null) && sWakelock.isHeld())
                sWakelock.release();
        };

        @Override
        protected Manifest doInBackground(Void... params)
        {
            ArrayList files = getFiles(....)// download the jsonfile, and return the list of files

            final String baseurl = ... //  get the remote base url
            final String baselocal = ... //get the local base path ;

            int tot = m.size();

            publishProgress(0, tot);

            final int MAX_THREADS = Runtime.getRuntime().availableProcessors(); * 4;

            ThreadPoolExecutor tpe = new ThreadPoolExecutor(
                            MAX_THREADS,
                            MAX_THREADS,
                            1,
                            TimeUnit.MINUTES,
                            new LinkedBlockingQueue<Runnable>()
                            );

            for (final String s: files)
            {

                tpe.submit(new Runnable()
                {
                    @Override
                    public void run()
                    {
                        try
                        {
                            URL remoteUrl = new URL(baseurl + s);
                            File localUrl = new File(baselocal, s);
                            FileUtils.copyURLToFile(remoteUrl, localUrl, 60000, 60000);
                            Log.w(TAG, "Downloaded " + localUrl.getAbsolutePath() + " in " + remoteUrl);
                        } catch (Exception e)
                        {
                            e.printStackTrace();
                            Log.e(TAG, "download error " + e);
                            // error management logic
                        }
                    }

                });
            }

            tpe.shutdown();
            int num = 0;
            publishProgress(num, tot);
            try
            {
                while (!tpe.awaitTermination(1, TimeUnit.SECONDS))
                {
                    int n = (int) tpe.getCompletedTaskCount();
                    Log.w(TAG, "COUTN:  " + n + "/" + tot);
                    if (n != num)
                    {
                        num = n;
                        publishProgress(num, tot);
                    }
                }
            } catch (InterruptedException e)
            {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }

            return m;
        }

        protected void onProgressUpdate(Integer... prog)
        {
       if (sProgress.getMax() != prog[1])                {
                sProgress.setMax(prog[1]);
            }
            sProgress.setProgress(prog[0]);
        }

        @Override
        protected void onPostExecute(Manifest result)
        {

            sWakelock.release();
            sProgress.hide();
            sProgress.dismiss();

            // manage results
        }
    }.execute();
}

【问题讨论】:

  • 那你做了什么朋友?我还需要在线程池执行期间更新进度。

标签: android android-asynctask threadpoolexecutor


【解决方案1】:

如果您检查 AsyncTask 的实现,那么您会发现 AsyncTask 本身具有 ThreadPool,因此它将在单独的线程上启动任务。实际上,当我们可以使用 .execute() 启动后台任务时,此方法通常与 THREAD_POOL_EXECUTOR 一起使用,以允许多个任务在 AsyncTask 管理的线程池上并行运行。那么为什么你需要实现另一个。

更新 阅读 this 中的 executeOnExecutor 可能对您有所帮助...它清楚地表明,如果您允许多个任务从线程池并行运行,通常不是人们想要的,因为它们的操作顺序没有定义....但是在这里您要下载文件,因此我认为顺序并不重要,因此在我看来您可以使用它并且不会产生任何问题。

【讨论】:

  • 我需要并行执行下载。我正在下载数千个非常小的文件,所以我花了很多时间打开和关闭通信和文件。并行下载 4 或 8 个文件的性能确实更好
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-01-29
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多