未收集 AsyncTasks 导致其他 AsyncTasks 无法运行 [英] AsyncTasks do not get collected causing other AsyncTasks to not run

查看:25
本文介绍了未收集 AsyncTasks 导致其他 AsyncTasks 无法运行的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我的应用使用了很多 AsyncTask.毕竟它是一个网络应用程序.当我跟踪调试选项卡时,我注意到每个 AsyncTask 都说在它后面运行,并且在 5 个 AsyncTasks 之后,我无法启动任何 AsyncTasks.我通过将执行程序更改为 THREAD_POOL_EXECUTOR 来修复它,这允许 15 个线程被合并.但是 AsyncTasks 仍然显示为正在运行.

My app uses a lot of AsyncTasks. It is a web app after all. And when I keep track of the Debug tab, I notice every AsyncTask says running behind it and after 5 AsyncTasks, I can't start any AsyncTasks. I fixed it by changing the executor to THREAD_POOL_EXECUTOR which allows 15 threads to be pooled. But the AsyncTasks still show as running.

AsyncTasks 中都有 InputStreams 和 BufferedReaders 来读取 JSON,但我从不调用 Streamers 和 Readers 上的 close() 方法.是这样吗,还是AsyncTask完成后会被回收?

The AsyncTasks all have InputStreams in them and BufferedReaders in them to read the JSON, but I never call the close() method on the Streamers and Readers. Could this be it, or will the AsyncTask be collected after it's finished no matter what?

如果是这样,为什么我不能在我的应用中运行超过 5 个 AsyncTask?

If that's the deal, then why can't I run more than 5 AsyncTasks in my app?

AsyncTasks 都经过它们的方法.除了 BasicNameValuePairs 不同之外,所有这些都以完全相同的方式构建.我 100% 确定代码中没有容易犯的错误.

The AsyncTasks all go through their methods. All of them are built the same exact way, except with different BasicNameValuePairs. I am 100% sure there is no easy mistake made in the code.

以下是其中一个 AsyncTask 的示例:

Here is an example of one of the AsyncTasks:

private class RunningEvent extends AsyncTask<Void, Void, Response> {

    @Override
    protected void onPreExecute() {
        if (Constants.isOnline(getApplicationContext())) {
            super.onPreExecute();
        } else {
            Toast.makeText(getApplicationContext(),
                    "No internet connection", Toast.LENGTH_LONG).show();
            return;
        }
    }

    @Override
    protected Response doInBackground(Void... empty) {
        HttpClient client = new DefaultHttpClient();
        HttpPost post = new HttpPost(URL);

        try {
            List<NameValuePair> values = new ArrayList<NameValuePair>(5);
            values.add(new BasicNameValuePair("tag", "eventRunning"));
            values.add(new BasicNameValuePair("userid", String
                    .valueOf(response.user.userid)));
            post.setEntity(new UrlEncodedFormEntity(values));

            HttpResponse httpresponse = client.execute(post);
            HttpEntity entity = httpresponse.getEntity();
            InputStream stream = entity.getContent();

            Log.i("MenuActivity",
                    "Input streamed, parsing Gson for existing events");
            Gson gson = new Gson();
            Reader reader = new InputStreamReader(stream);

            eventresponse = gson.fromJson(reader, Response.class);
            return eventresponse;
        } catch (Exception e) {
            e.printStackTrace();
            Log.e("RunningEvent", "Error sending data to Server");
        }
        return null;
    }

    @Override
    protected void onPostExecute(Response result) {
        // TODO Auto-generated method stub
        super.onPostExecute(result);
        Log.i("MenuActivity", "Binding button");
        if (eventresponse != null) {
            if (eventresponse.success == 1) {
                eventresponse.user = response.user;
                bActivity.setOnClickListener(new OnClickListener() {

                    public void onClick(View arg0) {
                        Intent i = new Intent("com.xxx.xxx.EVENT");
                        i.putExtra("response", eventresponse);
                        running = false;
                        switcher.cancel(true);
                        MenuActivity.this.finish();
                        startActivity(i);
                    }

                });
            } else {
                bActivity.setText("Nieuw activity");
                bActivity.setOnClickListener(new OnClickListener() {

                    public void onClick(View arg0) {
                        Intent i = new Intent("com.xxx.xxx.NEWEVENT");
                        i.putExtra("response", response);
                        running = false;
                        switcher.cancel(true);
                        MenuActivity.this.finish();
                        startActivity(i);
                    }

                });
            }
        } else {
            Log.i("RunningEvent", "Response is null");
        }
    }

}

上面的例子有时会作为第 6 个 AsyncTask 运行,它永远不会进入 doInBackground() 方法.我相信这是 SERIAL_EXECUTOR 的 5 Thread 限制.我通过将大多数 AsyncTasks 放在 THREAD_POOL_EXECUTOR 中修复"了这个问题,但这只是在避免它.

The example above is the sometimes gets runned as the 6th AsyncTask and it will never enter the doInBackground() method. I believe this is the 5 Thread limit of the SERIAL_EXECUTOR. I "fixed" the problem by putting most AsyncTasks in THREAD_POOL_EXECUTOR, but this is just avoiding it.

这些 AsyncTasks 永远不会停止运行并阻塞 Executor 的原因是什么?

What could be the reason that these AsyncTasks never stop running and clogging up the Executor?

推荐答案

android.os.AsyncTask 自带两个内置执行器.如果使用 SERIAL_EXECUTOR,则没有线程池,所有 AsyncTask 都按串行顺序一次执行一个.如果使用 THREAD_POOL_EXECUTOR(我想这就是您在问题中所指的),则最多允许并行执行 128 个 AsyncTask.

android.os.AsyncTask come with two built-in executor. if using SERIAL_EXECUTOR, there is no threadpool and all AsyncTask get execute one at a time in serial order. if using THREAD_POOL_EXECUTOR (I suppose this is what you refer in the question), this allows up to maximum 128 AsyncTask get execute in parallel.

你参考和调试看到的数字5是底层线程池的corePoolSize(AKA.THREAD_POOL_EXECUTOR),它不同于maximumPoolSize.查看 AsyncTask 源代码 并查看线程池是如何实现的:

The number 5 you refer and see from debugging is the corePoolSize of underlying threadpool (AKA. THREAD_POOL_EXECUTOR), which is different from maximumPoolSize. check out AsyncTask source code and see how threadpool is implemented:

private static final int CORE_POOL_SIZE = 5;
private static final int MAXIMUM_POOL_SIZE = 128;
private static final int KEEP_ALIVE = 1;

... ...

/**
 * An {@link Executor} that can be used to execute tasks in parallel.
 */
public static final Executor THREAD_POOL_EXECUTOR
        = new ThreadPoolExecutor(CORE_POOL_SIZE, MAXIMUM_POOL_SIZE, KEEP_ALIVE,
                TimeUnit.SECONDS, sPoolWorkQueue, sThreadFactory);

查看 ThreadPoolExecutor API 查看创建的默认线程池行为是什么通过调用这个构造函数.一般而言,corePoolSize 是要保留在池中的线​​程数,即使它们处于空闲状态,除非设置了 allowCoreThreadTimeOut .

Check out ThreadPoolExecutor API to see what is the default threadpool behavior created by calling this constructor. Generally speaking, corePoolSize is the number of threads to keep in the pool, even if they are idle, unless allowCoreThreadTimeOut is set.

您在调试中看到的那 5 个 AsyncTask 实际上位于已完成并变为空闲但从未终止的核心线程上,您可以通过调用 ThreadPoolExecutor.allowCoreThreadTimeOut(boolean).

Those 5 AsyncTask you see in debug are actually on core threads which are finished and become idle but never terminated, you can alter this behavior by calling ThreadPoolExecutor.allowCoreThreadTimeOut(boolean).

我说SERIAL_EXECUTOR不使用线程池,这不是真的.SERIAL_EXECUTOR 确实是将真正的工作委托给 THREAD_POOL_EXECUTOR,但是使用 ArrayDeque 来控制下一个任务的提交(如果上一个任务完成则提交下一个任务),查看源码:

I said SERIAL_EXECUTOR does not use threadpool, this is not true. SERIAL_EXECUTOR is indeed delegate the real work to THREAD_POOL_EXECUTOR, but using ArrayDeque to control the submission of next tasks (next task is submitted iff the previous task is finished), check out the source:

private static class SerialExecutor implements Executor {
    final ArrayDeque<Runnable> mTasks = new ArrayDeque<Runnable>();
    Runnable mActive;

    public synchronized void execute(final Runnable r) {
        mTasks.offer(new Runnable() {
            public void run() {
                try {
                    r.run();
                } finally {
                    scheduleNext();
                }
            }
        });
        if (mActive == null) {
            scheduleNext();
        }
    }

    protected synchronized void scheduleNext() {
        if ((mActive = mTasks.poll()) != null) {
            THREAD_POOL_EXECUTOR.execute(mActive);
        }
    }
}

因此,无论您使用 SERIAL_EXECUTOR 还是 THREAD_POOL_EXECUTOR,线程池中总会显示 5 个核心线程,即使它们已完成并空闲.但是,核心线程数(由corePoolSize 配置)不是当前线程池中运行的线程数(由maximumPoolSize 配置).

So whatever you use SERIAL_EXECUTOR or THREAD_POOL_EXECUTOR, there are always 5 core threads shown in threadpool even they are finished and become idle. However, number of core thread (configured by corePoolSize) is not the number of threads (configured by maximumPoolSize) currently running in threadpool.

这篇关于未收集 AsyncTasks 导致其他 AsyncTasks 无法运行的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆