2015-09-17 4 views
13

Я распараллеливаю свою операцию, разбивая ее на точное количество доступных сердечников, а затем, запустив такое же количество AsyncTask, выполнив ту же операцию, но на разных частях данных.Дождитесь завершения целого набора AsyncTask

Я использую executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, ...), чтобы распараллелить их выполнение.

Я хотел бы знать, когда каждая нить заканчивает работу, чтобы объединить все результаты и выполнить дальнейшие операции.

Как я могу это сделать?

+0

Если вы хотите ждать, то я предпочел бы использовать тему, как вы можете просто присоединиться нить. Весь смысл использования Async состоит в том, что он выполняется параллельно. Конечно, вы можете дождаться результата, используя Future for Async. –

+0

У вас есть контроль над 'AsyncTask' и знаете ли вы количество задач заранее? если это так, вы можете просто отсчитывать (целочисленная переменная, без необходимости причудливой синхронизации) количество готовых задач в 'onPostExecute()' и действовать, когда счетчик достигает нуля. – dhke

+0

@dhke в этом случае вам нужно запустить цикл простоя, и мне это не очень нравится –

ответ

12

Вы также можете просто уменьшаете счетчик в общем объекте как часть onPostExecute. Поскольку 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 ищет решение в котором он может избежать строительства нового класса. Это может быть сделано путем разделяя AtomicInteger среди порождены 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"));  
     } 
    } 
} 
+0

Я думаю, что таким образом у вас может возникнуть проблема множественного доступа и модификации одной и той же переменной несколькими потоками, если они будут завершены одновременно. –

+1

Нет, поскольку onPostExecute запускается в основном потоке. переменная как часть doInBackground. –

+0

Итак, вы предложите позволить активности ждать в холостом цикле, пока счетчик не достигнет нуля? Не уверен, что я s наилучшее решение тогда. –

4

Вы должны использовать CountDownLatch. Здесь документация с примерами: java.util.concurrent.CountDownLatch

В основном вы даете ссылку на CountDownLatch для ваших потоков, и каждый из них будет уменьшать его, когда закончил:

countDownLatch.countDown(); 

Основной поток будет ждать окончания всех с использованием:

countDownLatch.await(); 
+0

Каково его поведение в случае одновременного доступа к CountDownLatch? –

+0

Это потокобезопасность, так как CountDownLatch - это инструмент синхронизации. –

+0

Это решение очень интересно для меня, но проблема в том, что вы можете использовать его только в том случае, если у вас нет параметров для перехода к вашей AsyncTask (в моем случае я передаю своей задаче несколько целых чисел, и я не могу передать CountDownLatch в то же самое время время и ссылаться на него в 'onPostExecute' не работает должным образом –

0

Другим вариантом может быть сохранение всех ваших новых потоков в массиве.

Затем вы можете выполнить итерацию по массиву и подождать с потоком [i] .join для завершения потока.

см присоединиться() http://developer.android.com/reference/java/lang/Thread.html#Thread(java.lang.Runnable)

Когда итерация закончена все ваши нити сделаны и вы можете работать на

Смежные вопросы