AsyncTasks不会被收集,导致其他AsyncTasks无法运行

时间:2012-07-28 22:47:24

标签: java android garbage-collection android-asynctask threadpool

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

AsyncTasks中都有InputStreams,其中有BufferedReaders来读取JSON,但我从不在Streamer和Readers上调用close()方法。可能是这样,或者AsyncTask会在完成后收集吗?

如果这是交易,那为什么我不能在我的应用程序中运行超过5个AsyncTasks?

看到我给它一个赏金,我会更明确地解释这个

AsyncTasks都经历了他们的方法。除了BasicNameValuePairs之外,所有这些都以相同的方式构建。我100%确定代码中没有容易出错的错误。

以下是其中一个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()方法。我相信这是Thread的5 SERIAL_EXECUTOR限制。我通过将大多数AsyncTasks放在THREAD_POOL_EXECUTOR中来“解决”问题,但这只是避免它。

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

1 个答案:

答案 0 :(得分:8)

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

您从调试中引用和查看的数字5是底层线程池(AKA .THREAD_POOL_EXECUTOR)的corePoolSize,它与maximumPoolSize不同。查看AsyncTask source code并查看如何实现线程池:

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

你在debug中看到的那5个AsyncTask实际上是在完成并变为空闲但从未终止的核心线程上,你可以通过调用ThreadPoolExecutor.allowCoreThreadTimeOut(boolean)来改变这种行为。


关于SERIAL_EXECUTOR的更多故事

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

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配置)。