web-dev-qa-db-ja.com

複数のAsyncTaskが完了するのを待ちます

使用可能なコアの正確な数に分割して操作を並列化し、次に同じ数のAsyncTaskを開始して、同じ操作をデータの異なる部分で実行します。

それらの実行を並列化するためにexecuteOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, ...)を使用しています。

すべてのスレッドがジョブを終了して、すべての結果を組み合わせてさらに操作を実行できるようになる時期を知りたいです。

どのようにできるのか?

14
Nicholas Allio

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は新しいクラスの構築を回避できるソリューションを探しています。これは、スポーンされたAtomicIntegers間でAsyncTaskを共有することで実行できます。

// 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"));    
        }
    }
}
11
Janus Varmarken

CountDownLatchを使用する必要があります。ここに例のあるドキュメントがあります: Java.util.concurrent.CountDownLatch

基本的に、CountDownLatchの参照をスレッドに指定すると、各スレッドは終了時にスレッドをデクリメントします。

countDownLatch.countDown();

メインスレッドは、以下を使用してすべてのスレッドの終了を待機します。

countDownLatch.await();
5

まず、このクラスをプロジェクトに追加します

_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();
_

すべてのタスクが完了したときに実行されるコードをキャンセルする場合は、multiTaskHandler.cancel()を使用できます。たとえば、エラーが発生した場合(他のすべてのタスクもキャンセルすることを忘れないでください)。

*このソリューションはメインスレッドを一時停止しません!

2
Gil SH

RX マージ 演算子はあなたの友達です。

AsyncTarkの削除はRXよりも遅く、エラーを処理できません

0
Duna

別のオプションは、すべての新しいスレッドを配列に格納することです。

次に、配列を反復処理し、thread [i] .joinでスレッドが終了するのを待つことができます。

join()を参照 http://developer.Android.com/reference/Java/lang/Thread.html#Thread(Java.lang.Runnable)

反復が終了すると、すべてのスレッドが完了し、作業できるようになります

0
Andriel