2015-09-17 18 views
13

私は、使用可能なコアの数で分割して、同じ操作を実行して、データの異なる部分に対して同じ数のAsyncTaskを開始することで、操作を並列化しています。複数のAsyncTaskが完了するまで待ちます

私はexecuteOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, ...)を使用して、それらの実行を並列化しています。

すべてのスレッドがいつジョブを終了するかを知りたいので、すべての結果を結合してさらに操作を実行してください。

どうすればいいですか?

+0

あなたは待つしたい場合は、単にスレッドに参加できて、その後、私はスレッドを使用して好むだろう。 Asyncを使用することの全ポイントは、それが並行して実行されることです。もちろん、Future for Asyncを使用して結果を待つことができます。 –

+0

あなたは 'AsyncTask'を制御できますか?事前にタスクの数を知っていますか?そうであれば、onPostExecute()で終了したタスクの数をカウントダウン(整数変数、ファンシー同期化は不要)し、カウントがゼロになったときに動作します。 – dhke

+0

@dhkeこの場合、アイドルループを実行する必要があります。あまり好きではありません –

答えて

12

上で動作することができます終了しhttp://developer.android.com/reference/java/lang/Thread.html#Thread(java.lang.Runnable)

onPostExecuteは同じスレッド(メインスレッド)上で実行されるため、同期について心配する必要はありません。

UPDATE 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")); 
     } 
    } 
} 

UPDATE 2

この回答のコメントによると、OPは解決策を探しています新しいクラスの構築を避けることができます。これは、生成されたAsyncTaskの間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"));  
     } 
    } 
} 
+0

私は同じ方法で複数のスレッドが同時に終了した場合、同じ変数の複数のアクセスと変更に問題があると考えます。 –

+1

いいえ、onPostExecuteはメインスレッドで実行されます。 doInBackgroundの一部としての変数 –

+0

カウンタがゼロになるまでアクティビティをアイドルループで待機させることを提案しますか?それでは最高の解決策です。 –

4

CountDownLatchを使用する必要があります。ここでは例とドキュメント: java.util.concurrent.CountDownLatch

基本的に、あなたのスレッドにされたCountDownLatchの参照を与え、終了したら、それらのそれぞれは、それをデクリメントします:

countDownLatch.countDown(); 

メインスレッドがすべての終了時に待機しますスレッドを使用して:

countDownLatch.await(); 
+0

CountDownLatchへの同時アクセスの場合の動作は何ですか? –

+0

CountDownLatchは同期ツールなのでスレッドセーフです。 –

+0

このソリューションは非常に興味深いですが、問題は、AsyncTaskに渡すパラメータがない場合にのみ使用できることです(私の場合、私は自分のタスクにいくつかの整数を渡し、CountDownLatchを同じに渡すことはできません) 'onPostExecute'が' onPostExecute'で正しく動作しない場合があります –

0

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

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

)は(加入参照反復は、すべてのスレッドが行われ、あなたは、単にonPostExecuteの一環として、共有オブジェクト内のカウンタをデクリメントでき

関連する問題