Java 等待多个异步任务完成
我将操作并行化,方法是按可用内核的确切数量进行拆分,然后启动相同数量的AsyncTask,在数据的不同部分执行相同的操作 我正在使用Java 等待多个异步任务完成,java,android,multithreading,android-asynctask,Java,Android,Multithreading,Android Asynctask,我将操作并行化,方法是按可用内核的确切数量进行拆分,然后启动相同数量的AsyncTask,在数据的不同部分执行相同的操作 我正在使用executeOnExecutor(AsyncTask.THREAD\u POOL\u EXECUTOR,…)来并行执行它们 我想知道每个线程何时完成其工作,以便合并所有结果并执行进一步的操作 我该怎么办?你应该使用倒计时锁存器。以下是包含示例的文档: 基本上,你给你的线程一个倒计时锁存的引用,每个线程在完成后都会减少它: countDownLatch.count
executeOnExecutor(AsyncTask.THREAD\u POOL\u EXECUTOR,…)
来并行执行它们
我想知道每个线程何时完成其工作,以便合并所有结果并执行进一步的操作
我该怎么办?你应该使用倒计时锁存器。以下是包含示例的文档: 基本上,你给你的线程一个倒计时锁存的引用,每个线程在完成后都会减少它:
countDownLatch.countDown();
主线程将使用以下命令等待所有线程的终止:
countDownLatch.await();
另一种选择是将所有新线程存储在一个数组中 然后,您可以迭代数组并使用线程[i]等待。加入,等待线程完成 参见join()
迭代完成后,所有线程都完成了,您可以使用,也可以简单地减少共享对象中的计数器,作为
onPostExecute
的一部分。由于onPostExecute
在同一个线程(主线程)上运行,因此不必担心同步问题
更新1
共享对象可以如下所示:
public class WorkCounter {
private int runningTasks;
private final Context ctx;
public WorkCounter(int numberOfTasks, Context ctx) {
this.runningTasks = numberOfTasks;
this.ctx = ctx;
}
// Only call this in onPostExecute! (or add synchronized to method declaration)
public void taskFinished() {
if (--runningTasks == 0) {
LocalBroadcastManager mgr = LocalBroadcastManager.getInstance(this.ctx);
mgr.sendBroadcast(new Intent("all_tasks_have_finished"));
}
}
}
更新2
根据对这个答案的评论,OP正在寻找一种可以避免构建新类的解决方案。这可以通过在生成的AsyncTask
s之间共享AtomicInteger
来实现:
// TODO Update type params according to your needs.
public class MyAsyncTask extends AsyncTask<Void,Void,Void> {
// This instance should be created before creating your async tasks.
// Its start count should be equal to the number of async tasks that you will spawn.
// It is important that the same AtomicInteger is supplied to all the spawned async tasks such that they share the same work counter.
private final AtomicInteger workCounter;
public MyAsyncTask(AtomicInteger workCounter) {
this.workCounter = workCounter;
}
// TODO implement doInBackground
@Override
public void onPostExecute(Void result) {
// Job is done, decrement the work counter.
int tasksLeft = this.workCounter.decrementAndGet();
// If the count has reached zero, all async tasks have finished.
if (tasksLeft == 0) {
// Make activity aware by sending a broadcast.
LocalBroadcastManager mgr = LocalBroadcastManager.getInstance(this.ctx);
mgr.sendBroadcast(new Intent("all_tasks_have_finished"));
}
}
}
//TODO根据需要更新类型参数。
公共类MyAsyncTask扩展了AsyncTask{
//应在创建异步任务之前创建此实例。
//它的开始计数应等于将生成的异步任务数。
//重要的是,为所有派生的异步任务提供相同的AtomicInteger,以便它们共享相同的工作计数器。
专用最终原子整数工作计数器;
公共MyAsyncTask(AtomicInteger工作计数器){
this.workCounter=工作计数器;
}
//TODO机具DOIN背景
@凌驾
PostExecute上的公共作废(作废结果){
//工作完成后,减小工作计数器。
int tasksLeft=this.workCounter.decrementAndGet();
//如果计数已达到零,则所有异步任务都已完成。
如果(tasksLeft==0){
//通过发送广播使活动知晓。
LocalBroadcastManager mgr=LocalBroadcastManager.getInstance(this.ctx);
经理发送广播(新意图(“所有任务已完成”);
}
}
}
首先,将此类添加到项目中
public abstract class MultiTaskHandler {
private int mTasksLeft;
private boolean mIsCanceled = false;
public MultiTaskHandler(int numOfTasks) {
mTasksLeft = numOfTasks;
}
protected abstract void onAllTasksCompleted();
public void taskComplete() {
mTasksLeft--;
if (mTasksLeft==0 && !mIsCanceled) {
onAllTasksCompleted();
}
}
public void reset(int numOfTasks) {
mTasksLeft = numOfTasks;
mIsCanceled=false;
}
public void cancel() {
mIsCanceled = true;
}
}
然后:
int totalNumOfTasks = 2; //change this to the number of tasks that you are running
final MultiTaskHandler multiTaskHandler = new MultiTaskHandler(totalNumOfTasks) {
@Override
protected void onAllTasksCompleted() {
//put the code that runs when all the tasks are complete here
}
};
然后在每个任务中-完成后,添加以下行:multiTaskHandler.taskComplete()代码>
例如:
(new AsyncTask<Void,Void,Void>() {
@Override
protected Void doInBackground(Void... voids) {
// do something...
return null;
}
@Override
protected void onPostExecute(Void aVoid) {
multiTaskHandler.taskComplete();
}
}).execute();
(新的异步任务(){
@凌驾
受保护的空位背景(空位…空位){
//做点什么。。。
返回null;
}
@凌驾
受保护的void onPostExecute(void避免){
multiTaskHandler.taskComplete();
}
}).execute();
如果要取消所有任务完成后运行的代码,可以使用multiTaskHandler.cancel()
。例如,如果您有一个错误(不要忘记取消所有其他任务)
*此解决方案不会暂停主线程接收操作员是您的朋友
摆脱AsyncTark比RX慢,并且您无法处理错误如果您想等待,那么我更喜欢使用线程,因为您可以简单地加入一个线程。使用Async的关键在于它是并行执行的。当然,您可以使用Future for Async等待结果。您是否可以控制AsyncTask
s,并且您是否提前知道任务的数量?如果是这样,您可以在onPostExecute()
中倒计时(整数变量,无需复杂的同步)已完成任务的数量,并在计数为零时采取行动。@dhke在这种情况下,您必须运行一个空闲循环,我也不喜欢它much@NicholasAllio这是指我删除的评论吗?如果是:是的,我从您对答案的评论中意识到,您希望得到通知,而不是等待。使用Rx merge Operator或者这样认为,如果多个线程同时完成,您可能会遇到多个访问和修改同一变量的问题。否,因为onPostExecute在主线程上运行。只是不要作为doInBackground的一部分访问变量。那么您会建议让活动在空闲循环中等待,直到计数器达到零?不确定是不是最好的解决方案……不,那绝对不是一个好的解决方案(事实上,由于无响应,系统可能会关闭活动)。作为在共享对象中设置计数器的一部分,您可以检查更新后的值是否已达到0。如果是这样的话,,做一个本地广播,在你的活动中收听。当然这会起作用,但我正在寻找更方便的方法在并发访问CountDownLatch时它的行为是什么?它是线程安全的,因为CountDownLatch是一个同步工具。这个解决方案对我来说非常有趣,但问题是你只能使用它如果没有要传递给AsyncTask的参数(在我的例子中,我向我的任务传递了几个整数,但我不能同时传递倒计时锁存器并在onPostExecute
中引用它,因为它工作不正常。您可以扩展AsyncTask并创建一个带有额外参数的构造函数,并通过调用'super.onPostExecute()重写onPostExecute。)'然后是'countDownLatch.countDown()'。“主线程将使用:countDownLatch.await()
”在所有线程终止时等待。实际上,您需要为这个await
调用指定一个独立的线程,而不是主线程,否则您将无法使用