Как я могу включить, чтобы остановить мой работающий код? - PullRequest
0 голосов
/ 01 августа 2011

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

Как это сделать? Есть ли шаблон дизайна для этого?

Примечание. Некоторые из выполняющихся кодов можно отменить, а некоторые - нет. Как мне найти компромисс вокруг этого?

РЕДАКТИРОВАТЬ : Я должен был сказать, что хочу немедленно прекратить операцию.

Ответы [ 4 ]

3 голосов
/ 01 августа 2011

Чтобы подвести итог и расширить сказанное Джоном:

  • Вы должны сообщить потоку, что он должен выйти из цикла (флаг volatile).
  • Вы можете interrupt()поток , если вы хотите, чтобы он вышел из состояния блокировки.
  • Вы должны обработать InterruptedException внутри метода run.
  • Вы должны выйти изящнокогда вас прерывают (т.е. заканчивают все, что вы делаете, и убирайте).

Какой-то код:

private volatile bool _running;// volatile guarantees that the flag will not be cached

public void kill(){_running = false;}
public void run()
{
    while(_running)
    {        
        try
        {
            DoWork(); // you may need to synchronize here
        }
        catch(InterruptedException e)
        {
            // Handle e
        }
    }
}
2 голосов
/ 01 августа 2011

(я предполагаю, что вы уже выполняете фоновую работу в отдельном потоке.)

По сути, вы сохраняете общий флаг boolean, который поток пользовательского интерфейса может устанавливать, и фоновый поток периодически читает,Когда флаг говорит «стоп», вы останавливаетесь:)

Обратите внимание, что флаг должен быть изменчивым, или вы должны использовать блокировку, чтобы убедиться, что фоновый поток определенно «видит» изменения, записанные из пользовательского интерфейса.thread.

Это довольно грубо и выглядит немного "ручным", но это означает, что вы не рискуете нестабильностью, прерывая половину операции, в отличие от таких подходов, как Thread.stop().

0 голосов
/ 24 декабря 2012

Мои 2 цента.Задача, которую можно отменить.cancelImpl() и runImpl() должны быть реализованы.

import java.util.concurrent.CancellationException;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicInteger;

public abstract class CancelableTask extends Observable<CancelableTask>
        implements Runnable {
    private volatile boolean isStarted = false;
    private volatile boolean isCanceled = false;
    private volatile boolean isSuccess = false;
    private volatile Exception e;
    private volatile AtomicBoolean doneLock = new AtomicBoolean(false);
    protected final AtomicInteger progress = new AtomicInteger(0);

    public CancelableTask() {
    }

    @Override
    public final void run() {
        try {
            runUnsafe();
        } catch (Exception e) {
            Config.getLog().i("CancelableTask threw an exception", e);          
        }
    }

    public final void runUnsafe() throws Exception {
//      Config.getLog().d("Running cancelable task: " + toString());
        notifyObservers(this);
        isStarted = true;
        try {
            if (!isCanceled) {
                runImpl();
            }
        } catch (Exception e) {
            // Note: Cancel may throw exception
            if (doneLock.compareAndSet(false, true)) {
                this.e = e;
                notifyObservers(this);
                clearObservers();
                // Someone else should do something with the exception
//              Config.getLog().i("Failed cancelable task: " + toString(), e);
                throw e;
            }
            // Cancel got to the lock first but may NOT have yet changed the cancel flag.
            // Must throw cancellation exception.
        }
        if (doneLock.compareAndSet(false, true)) {
            isSuccess = true;
            progress.set(100);
            notifyObservers(this);
            clearObservers();
//          Config.getLog().d("Finished cancelable task: " + toString());
            return;
        }

        // The task was canceled but the isCanceled may not have been set yet.

        synchronized (doneLock) { // Waiting for the cancel to finish it's logic
        }

//      assert isCanceled; // Commented out because android crashes the app in assertion 
        // No need to notify here because cancel was already notified in
        // cancel method.
        // notifyObservers(this);
//      Config.getLog().d("Already canceled task: " + toString());
        throw new CancellationException("Canceled while running!");
    }

    protected abstract void runImpl() throws Exception;

    protected void cancelImpl() {}

    public final void cancel() {
        synchronized (doneLock) {
            if (doneLock.compareAndSet(false, true)) {
//              Config.getLog().i("Canceling cancelable task: " + toString());
                isCanceled = true;

                cancelImpl();

                notifyObservers(this);

                clearObservers();
            }
        }
    }

    public final boolean isCanceled() {
        return isCanceled;
    }

    public final boolean isSuccessful() {
        return isSuccess;
    }

    public final boolean isDone() {
        return doneLock.get();
    }

    public final boolean isStarted() {
        return isStarted;
    }

    public final Exception getError() {
        return e;
    }

    public int getProgress() {
        return progress.get();
    }

    /**
     * Observers will be cleared after the task is done but only after all of them are notified.
     */
    @Override
    public void addObserver(Observer<CancelableTask> observer) {
        super.addObserver(observer);
    }


//  protected void incrementProgress(int value) {
//      progress += value;
//  }
}

Также существует коллекция CancelableCollection:

import java.util.Collection;
import java.util.LinkedHashMap;
import java.util.Map.Entry;
import java.util.concurrent.CancellationException;

public class CancelableCollection extends CancelableTask {
    private LinkedHashMap<CancelableTask, Integer> cancelables = new LinkedHashMap<CancelableTask, Integer>();
    private volatile boolean normalizing;
    private volatile State state = new State(null, 0, 0);
    private boolean isOneFailsAll = true;

//  public boolean isOneFailsAll() {
//      return isOneFailsAll;
//  }

    public void setOneFailsAll(boolean isOneFailsAll) {
        this.isOneFailsAll = isOneFailsAll;
    }

    public int getTotalWeight() {
        Collection<Integer> values = cancelables.values();
        int total = 0;
        for (int weight : values) {
            total += weight;
        }
        return total;
    }

    /**
     * Adds and runs the cancelable
     * 
     * @param cancelable
     * @return
     * @throws Exception
     *             if failed while running
     * @throws CancellationException
     *             if already canceled
     */
    public void add(CancelableTask cancelable, int relativeTime) {
        if (cancelable == null) {
            return;
        }
        cancelables.put(cancelable, relativeTime);

        if (isCanceled()) {
            throw new CancellationException("Canceled while running!");
        }

        if (isDone()) {
            throw new RuntimeException(
                    "Cannot add tasks if the Cancelable collection is done running");
        }

        if (normalizing) {
            throw new RuntimeException(
                    "Cannot add tasks if already started normalizing");
        }
    }

    @Override
    protected void runImpl() throws Exception {
        normalizeProgress();
        for (Entry<CancelableTask, Integer> entry : cancelables.entrySet()) {
            int currentRelativeTime = entry.getValue();
            CancelableTask currentTask = entry.getKey();
            // Advance the state to the next one with the progress from the
            // previous one.
            state = new State(currentTask, currentRelativeTime, state.getProgress());
            try {
                currentTask.runUnsafe();
            } catch (Exception e) {
                if (isOneFailsAll) {
                    throw e;
                }
                Config.getLog().i("Task failed but continueing with other tasks", e);
            }
        }
        state = new State(null, 0, 100);
    }

    private void normalizeProgress() {
        normalizing = true;
        int overall = 0;
        for (Entry<CancelableTask, Integer> entry : cancelables.entrySet()) {
            overall += entry.getValue();
        }
        double factor = overall == 0 ? 1 : (double)100 / overall;
        for (Entry<CancelableTask, Integer> entry : cancelables.entrySet()) {
            entry.setValue((int) (entry.getValue() * factor));
        }
    }

    @Override
    protected void cancelImpl() {
        for (CancelableTask cancelable : cancelables.keySet()) {
            cancelable.cancel();
        }
    }

    @Override
    public int getProgress() {
        int progress = this.progress.get();
        int stateProgress = state.getProgress();
        this.progress.compareAndSet(progress, stateProgress); // Setting this value just for easier debugging. I has no meaning in CancelableCollection
        return super.getProgress();
    }

    private static class State {
        private CancelableTask currentTask;
        private int currentRelativeTime;
        private int progress;

        public State(CancelableTask currentTask, int currentRelativeTime,
                int progress) {
            super();
            this.currentTask = currentTask;
            this.currentRelativeTime = currentRelativeTime;
            this.progress = progress;
        }

        public int getProgress() {
            return progress
                    + (currentTask == null ? 0 : (int)(currentTask.getProgress()
                            * (double)currentRelativeTime / 100));
        }
    }
}
0 голосов
/ 01 августа 2011

остановите поток или асинхронную задачу, которую вы используете, или вызовите this.finish

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...