等待取消的未来实际完成

我有一个SwingWorker调用一些不检查线程中断的代码。 在调用worker.cancel(true)worker.get()方法将立即抛出CancellationException (正如它应该的那样)。 但是,由于后台任务的代码从不检查其线程是否被中断,因此它很乐意继续执行。

是否存在等待后台任务实际完成的标准方法? 我希望显示一个“正在取消……”消息或类似的东西,直到任务终止。 (我确信如果有必要,我可以在工人类中使用标志来完成此操作,只需查找其他任何解决方案。)

我玩了一下这个,这就是我想出来的。 我正在使用CountDownLatch并基本上将其await()方法暴露为我的SwingWorker对象上的方法。 仍在寻找更好的解决方案。

 final class Worker extends SwingWorker { private final CountDownLatch actuallyFinishedLatch = new CountDownLatch(1); @Override protected Void doInBackground() throws Exception { try { System.out.println("Long Task Started"); /* Simulate long running method */ for (int i = 0; i < 1000000000; i++) { double d = Math.sqrt(i); } return null; } finally { actuallyFinishedLatch.countDown(); } } public void awaitActualCompletion() throws InterruptedException { actuallyFinishedLatch.await(); } public static void main(String[] args) { Worker worker = new Worker(); worker.execute(); try { TimeUnit.SECONDS.sleep(1); } catch (InterruptedException e) { } System.out.println("Cancelling"); worker.cancel(true); try { worker.get(); } catch (CancellationException e) { System.out.println("CancellationException properly thrown"); } catch (InterruptedException e) { } catch (ExecutionException e) { } System.out.println("Awaiting Actual Completion"); try { worker.awaitActualCompletion(); System.out.println("Done"); } catch (InterruptedException e) { } } } 

与标准或现成方法最接近的是SwingWorker提供的progress属性和/或发布/进程方法对。 您可以在方法结束时将其设置为“我已完成”值,以指示后台工作已完成。 等待swing工作者的线程可以发出“正在取消…”消息并定期检查进度以查看它是否已完成。 如果等待线程是摆动EDT,那么您将需要使用Timer定期检查progress属性并在完成后清除取消消息。

下面是一些运行顽固后台线程的示例代码,该线程被取消,然后等待进度达到100。

 @Test public void testSwingWorker() { SwingWorker worker = new SwingWorker() { @Override protected void process(List chunks) { for (Object chunk : chunks) { System.out.println("process: "+chunk.toString()); } } @Override protected void done() { System.out.println("done"); } @Override protected Object doInBackground() throws Exception { // simulate long running method for (int i=0; i<1000000000; i++) { double d = Math.sqrt(i); } System.err.println("finished"); publish("finished"); setProgress(100); return null; } }; Thread t = new Thread(worker); t.start(); try { worker.get(1, TimeUnit.SECONDS); } catch (InterruptedException e) { } catch (ExecutionException e) { } catch (TimeoutException e) { } worker.cancel(true); // now wait for finish. int progress = 0; do { try { Thread.sleep(1000); } catch (InterruptedException e) { } progress = worker.getProgress(); System.out.println(String.format("progress %d", progress)); } while (progress<100); } 

另一种方法是使用publish\process方法对来推送一个特殊值,指示后台线程已完成EDT。 然后,您在SwingWorker中的process覆盖方法将获取此特殊值并隐藏“正在取消...”消息。 这样做的好处是不需要轮询或定时器。 示例代码显示尽管done取消任务后立即调用done ,但即使取消任务,发布/处理方法对仍然有效。

受Paul Blessing解决方案的启发,我将它改进了一点,成为一个类,你可以子类化以获得所需的function:

 class AwaitingWorker extends SwingWorker { private final CountDownLatch actuallyFinishedLatch = new CountDownLatch(1); /** * Override this to do something useful */ protected abstract void performOperation(); @Override protected final T doInBackground() throws Exception { try { return performOperation(); } finally { actuallyFinishedLatch.countDown(); } } public void awaitActualCompletion() throws InterruptedException { actuallyFinishedLatch.await(); } }