5

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

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

通常我会使用 SwingWorker,但我正在为 Grails 应用程序使用 Java/Groovy 后端,我不确定它在无头服务器环境中的行为如何,因为它具有 EDT 关系。

另一个例子是 Eclipse RCP 中的 Jobs 框架,但我需要一些与 UI 无关的东西。

4

4 回答 4

3

嘿,您可以尝试实现观察者模式,并让感兴趣的各方订阅工作线程(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);
}

更多信息:维基百科上的观察者模式

于 2010-01-05T02:14:14.540 回答
1

为什么不直接使用回调?启动后台任务时,将带有回调函数的对象传递给任务,并让任务以这种方式报告进度。没有任何涉及的 UI,您无需更改线程即可。

于 2010-01-05T01:52:47.690 回答
0

Adrian 和 edwardTheGreat 的答案都是不错的选择。这完全取决于您希望“其他代码”如何使用状态更新。第三种选择是使用消息队列,后台线程将定期状态写入其中。一个真正通用的版本将使用 JMS。

于 2010-01-05T03:42:09.697 回答
0

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

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

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

于 2017-05-23T15:18:56.383 回答