让我看看我是否正确理解了这个问题。您有一个 FIFO 任务队列,其中只有最旧的任务正在运行。每个任务完成后都需要更新 UI。但是如果某个用户事件进来了,所有的任务都需要被取消——也就是正在运行的任务需要被取消,尚未运行的任务需要从队列中移除。是对的吗?
假设是这样,我不会使用,SwingWorker
因为您只需要一个工作线程,而不是每个任务一个。FutureTask
应该足够了(假设您重写done()
以进行必要的调用SwingUtilities.invokeLater()
并进行 UI 更新)。
如果你取消 a FutureTask
,那么即使它的run()
方法被调用,它也不会做任何事情。因此,您可以FutureTask
安全地将 s 提交给ExecutorService
知道即使执行程序尝试运行它们,取消也会起作用。
我怀疑一个足够好的解决方案只是保留所有FutureTasks
可能需要取消的列表,并在用户事件出现时将它们全部取消。ExecutorService
仍然会尝试运行它们,但基本上不会-操作。您需要确保已从列表中删除已完成的任务,并且您需要确保列表已更新并以线程安全的方式使用(可能来自将任务放在的同一线程ExecutorService
),但这不应该是太难。
我只用了一个小时就把下面的代码搞砸了,我不敢打赌它是正确的,但你明白了。:)
/** Untested code! Use at own risk. */
public class SwingTaskExecutor {
// ////////////////////////////////////////////////////////////
// Fields
private final ExecutorService execSvc = Executors.newFixedThreadPool(1);
private final Lock listLock = new ReentrantLock();
private final List<ManagedSwingTask<?>> activeTasks =
new ArrayList<ManagedSwingTask<?>>();
// ////////////////////////////////////////////////////////////
// Public methods
public <T> Future<T> submit(SwingTask<T> task) {
ManagedSwingTask<T> managedTask = new ManagedSwingTask<T>(task);
addToActiveTasks(managedTask);
execSvc.submit(managedTask);
return managedTask;
}
public void cancelAllTasks() {
listLock.lock();
try {
for (ManagedSwingTask<?> t: activeTasks) {
t.cancel(true);
}
activeTasks.clear();
} finally {
listLock.unlock();
}
}
// ////////////////////////////////////////////////////////////
// Private methods
private <T> void addToActiveTasks(ManagedSwingTask<T> managedTask) {
listLock.lock();
try {
activeTasks.add(managedTask);
} finally {
listLock.unlock();
}
}
// ////////////////////////////////////////////////////////////
// Helper classes
private class ManagedSwingTask<T> extends FutureTask<T> {
private final SwingTask<T> task;
ManagedSwingTask(SwingTask<T> task) {
super(task);
this.task = task;
}
@Override
public void cancel(boolean mayInterruptIfRunning) {
try {
task.cancel();
} finally {
super.cancel(mayInterruptIfRunning);
}
}
@Override
protected void done() {
removeFromActiveTasks();
updateUIIfDone();
}
private void removeFromActiveTasks() {
listLock.lock();
try {
activeTasks.remove(this);
} finally {
listLock.unlock();
}
}
private void updateUIIfDone() {
if (isDone()) {
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
task.updateUI();
}
});
}
}
}
public static interface SwingTask<T> extends Callable<T> {
/** Called from the EDT if task completes successfully */
void updateUI();
/** Hook in case there's task-specific cancellation to be done*/
void cancel();
}
}
反正就是这样。
如果您想更加确定,则可以关闭并更换ExecutorService
,但这可能没有必要。