How can I report progress from a background task?

时间秒杀一切 提交于 2019-12-05 18:00:17

Hey you could possibly try and implement the Observer Pattern and have interested parties subscribe to the worker thread (extension of java.util.Observable or similar) or another Class that manages the observers.

You could use java.util.Observer and java.util.Observable or roll your own.

Simple Example of some Interfaces implementing the Observer Pattern:

public interface ObservableSubject<T extends SubjectObserver, V> {

   void registerObserver(T observer);

   void removeObserver(T observer);

   void notifyObservers(V notificationPayload); 

}


public interface SubjectObserver<T> {

   void handleNotification(T notificationPayload);
}

More info: Observer Pattern on Wikipedia

Why not just use a callback? When starting the background task, pass an object with a callback function to the task and let the task report progress that way. Without any involved UI you dont need to change thread to do so.

The answers from Adrian and edwardTheGreat are both good options. It all depends on how you want the "other code" to consume status updates. A third option is to use a message queue into which the background thread writes periodic status. A really general version of this would use JMS.

I designed a simple interface for this:

public interface Process<TState, TResult> {

    void onProgress(final Consumer<TState> callback);

    void onCompletion(final Consumer<TResult> callback);
}

The usage is like this:

final Process<Float, Either<IOException, String>> p = download(executor, url);

p.onProgress(progress -> {
    System.out.println("Progress: " + progress * 100);
});

p.onComplete(result -> {
    System.out.println("Finished: " + result.toString());
});

And an generic implementation, which should be thread-safe:

import com.google.common.base.Preconditions;

import java.util.ArrayList;
import java.util.List;
import java.util.function.Consumer;

public final class SettableProcess<TState, TResult> implements Process<TState, TResult> {

    private final Object LOCK = new Object();

    private final List<Consumer<TState>> progressCallbacks;
    private final List<Consumer<TResult>> completionCallbacks;

    private volatile boolean isComplete;
    private volatile TResult result;

    private SettableProcess() {

        progressCallbacks = new ArrayList<>();
        completionCallbacks = new ArrayList<>();

        isComplete = false;
        result = null;
    }

    @Override
    public void onProgress(final Consumer<TState> callback) {
        Preconditions.checkNotNull(callback);
        if (!isComplete) {
            synchronized (LOCK) {
                if (!isComplete) {
                    progressCallbacks.add(callback);
                }
            }
        }
    }

    @Override
    public void onCompletion(final Consumer<TResult> callback) {
        Preconditions.checkNotNull(callback);
        synchronized (LOCK) {
            if (isComplete) {
                callback.accept(result);
            } else {
                completionCallbacks.add(callback);
            }
        }
    }

    public void complete(final TResult result) {
        Preconditions.checkNotNull(result);
        Preconditions.checkState(!isComplete);
        synchronized (LOCK) {
            Preconditions.checkState(!isComplete);
            this.isComplete = true;
            this.result = result;
            for (final Consumer<TResult> callback : completionCallbacks) {
                callback.accept(result);
            }
        }
        completionCallbacks.clear();
        progressCallbacks.clear();
    }

    public void progress(final TState state) {
        Preconditions.checkNotNull(state);
        Preconditions.checkState(!isComplete);
        synchronized (LOCK) {
            Preconditions.checkState(!isComplete);
            for (final Consumer<TState> callback : progressCallbacks) {
                callback.accept(state);
            }
        }
    }

    public static <TState, TResult> SettableProcess<TState, TResult> of() {
        return new SettableProcess<>();
    }
}

This could be extended to support cancellation and so on.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!