我有一个SwingWorker
调用一些不检查线程中断的代码。调用worker.cancel(true)
后,worker.get()
方法会立即抛出CancellationException
(按照预期)。但是,由于后台任务的代码从不检查其线程是否被中断,因此很高兴继续执行。
是否存在等待后台任务实际完成的标准方法?我希望显示一个“正在取消...”消息或类似的东西,并阻止任务终止。 (我确信如果有必要,我可以随时在工人类中使用标志来完成此操作,只需查找其他任何解决方案。)
答案 0 :(得分:3)
我玩了一下这个,这就是我想出来的。我正在使用CountDownLatch
并基本上将其await()
方法公开为我的SwingWorker
对象上的方法。仍在寻找更好的解决方案。
final class Worker extends SwingWorker<Void, Void> {
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) {
}
}
}
答案 1 :(得分:1)
与标准或现成方法最接近的是progress
属性和/或SwingWorker
提供的发布/处理方法对。您可以在方法结束时将其设置为“我已完成”值,以指示后台工作已完成。等待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
,但即使任务被取消,发布/处理方法对仍然有效。
答案 2 :(得分:1)
受到Paul Blessing解决方案的启发,我将它改进了一点,成为一个类,你可以通过子类来获得所需的功能:
class AwaitingWorker<T,V> extends SwingWorker<T, V> {
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();
}
}