我有一个在ExecutorService线程池后台执行的长时间运行的任务。返回进度或中间结果的这项任务有哪些最佳实践?有没有提供此功能的库?
编辑:澄清一下,我说的是向其他代码报告进度,而不是向用户报告。
通常我会使用SwingWorker,但我正在使用Grails应用程序的Java / Groovy后端,我不确定它在无头服务器环境中会如何表现,因为它具有EDT关系。
另一个例子是Eclipse RCP中的Jobs框架,但是我需要一些与UI无关的东西。
答案 0 :(得分:3)
嘿,您可以尝试实现Observer Pattern并让感兴趣的各方订阅工作线程(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);
}
答案 1 :(得分:1)
为什么不使用回调?启动后台任务时,将具有回调函数的对象传递给任务,并让任务报告以此方式进行。没有任何涉及的UI,您不需要更改线程来执行此操作。
答案 2 :(得分:0)
Adrian和EdwardTheGreat的答案都是不错的选择。这一切都取决于您希望“其他代码”消耗状态更新的方式。第三种选择是使用后台线程写入周期状态的消息队列。一个非常通用的版本将使用JMS。
答案 3 :(得分: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<>();
}
}
这可以扩展到支持取消等等。