Подтвердить что ты не робот

Подождите, пока закончится несколько AsyncTask.

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

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

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

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

4b9b3361

Ответ 1

Вы также можете просто уменьшить счетчик в общем объекте как часть 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 ищет решение, в котором он может избежать создания нового класса. Это можно сделать, разделив AtomicInteger среди порожденных AsyncTask s:

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

Ответ 2

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

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

countDownLatch.countDown();

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

countDownLatch.await();

Ответ 3

Сначала добавьте этот класс в свой проект

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(), если хотите отменить код, который запускается, когда все задачи завершены. Например, если у вас есть ошибка (не забудьте также отменить все другие задачи).

* Это решение не остановит основной поток!

Ответ 4

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

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

см. join() http://developer.android.com/reference/java/lang/Thread.html#Thread(java.lang.Runnable)

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

Ответ 5

RX оператор слияния - ваш друг.

Избавиться от AsyncTark медленнее, чем RX, и вы не можете обрабатывать ошибки