2

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

AsyncTasks 中都有 InputStreams 和 BufferedReaders 来读取 JSON,但我从未close()在 Streamers 和 Readers 上调用该方法。可能是这样,还是无论如何都会在完成后收集AsyncTask?

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

看到我悬赏它,我将更明确地解释这一点

所有人都通过他们的AsyncTasks方法。除了使用不同的BasicNameValuePairs. 我 100% 确定代码中没有简单的错误。

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

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()方法。我相信这是 5 的Thread限制SERIAL_EXECUTOR。我通过投入大部分AsyncTasks来“解决”问题THREAD_POOL_EXECUTOR,但这只是在避免它。

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

4

1 回答 1

8

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

您在调试中看到的数字 5 是底层线程池的 corePoolSize(AKA. THREAD_POOL_EXECUTOR),它与 maximumPoolSize 不同。查看AsyncTask 源代码,看看线程池是如何实现的:

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

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


更多关于 SERIAL_EXECUTOR 的故事

我说SERIAL_EXECUTOR 不使用线程池,这不是真的。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 配置)。

于 2012-09-01T23:56:57.947 回答