代码之家  ›  专栏  ›  技术社区  ›  Ajay

如何报告后台任务的进度?

  •  4
  • Ajay  · 技术社区  · 15 年前

    我有一个长时间运行的任务,它在ExecutorService线程池的后台执行。对于返回进度或中间结果的任务,有哪些最佳实践?是否有提供此功能的库?

    编辑:为了澄清这一点,我说的是向其他代码报告进度,而不是向用户报告。

    通常我会使用SaveWrWork,但我正在为GRAIPS应用程序使用Java/Groovy后端,而且我不确定它如何在无头服务器环境中运行,因为它具有EDT-Type。

    另一个例子是EclipseRCP中的Jobs框架,但是我需要一些与UI不相关的东西。

    4 回复  |  直到 15 年前
        1
  •  3
  •   edwardsmatt    15 年前

    嘿,您可以尝试并实现观察者模式,让相关方订阅工作线程(java.util.observable或类似的扩展)或管理观察者的另一个类。

    您可以使用java.util.observer和java.util.observable 或者自己滚。

    实现观察者模式的一些接口的简单示例:

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

    更多信息: Observer Pattern on Wikipedia

        2
  •  1
  •   akuhn    15 年前

    为什么不使用回调?启动后台任务时,将带有回调函数的对象传递给该任务,并让该任务以这种方式报告进度。没有任何相关的UI,您不需要更改线程来完成此操作。

        3
  •  0
  •   Jim Garrison    15 年前

    阿德里安和爱德华大帝的回答都是很好的选择。这完全取决于您希望“其他代码”如何使用状态更新。第三种选择是使用消息队列,后台线程将定期状态写入其中。一个真正通用的版本将使用JMS。

        4
  •  0
  •   sdgfsdh    7 年前

    我为此设计了一个简单的界面:

    public interface Process<TState, TResult> {
    
        void onProgress(final Consumer<TState> callback);
    
        void onCompletion(final Consumer<TResult> callback);
    }
    

    用法如下:

    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());
    });
    

    以及一个通用的实现,它应该是线程安全的:

    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<>();
        }
    }
    

    这可以扩展到支持取消等等。