我的应用使用了很多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
的原因是什么?
答案 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不使用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配置)。