Java 等待被取消的未来真正结束

Java 等待被取消的未来真正结束,java,future,swingworker,Java,Future,Swingworker,我有一个SwingWorker,它调用一些不检查线程中断的代码。调用worker.cancel(true)后,worker.get()方法将立即抛出CancellationException。然而,由于后台任务的代码从不检查其线程是否被中断,因此它很高兴地继续执行 是否有一种标准的方法来等待后台任务实际完成?我希望显示一条“取消…”消息或类似的消息,直到任务终止。(如果有必要,我肯定我可以在worker类中使用一个标志来完成这项工作,只需寻找任何其他解决方案。)最接近标准或现成的方法是progr

我有一个
SwingWorker
,它调用一些不检查线程中断的代码。调用
worker.cancel(true)
后,
worker.get()
方法将立即抛出
CancellationException
。然而,由于后台任务的代码从不检查其线程是否被中断,因此它很高兴地继续执行


是否有一种标准的方法来等待后台任务实际完成?我希望显示一条“取消…”消息或类似的消息,直到任务终止。(如果有必要,我肯定我可以在worker类中使用一个标志来完成这项工作,只需寻找任何其他解决方案。)

最接近标准或现成的方法是
progress
属性和/或
SwingWorker
提供的发布/处理方法对。您可以在方法末尾将其设置为“I'm finished”值,以指示后台工作已完成。等待swing worker的线程可以显示一条“Canceling…”消息,并定期检查进度以查看是否已完成。如果等待线程是swing EDT,则需要使用计时器定期检查progress属性,并在完成时清除cancel消息

下面是一些运行顽固后台线程的示例代码,该线程被取消,然后等待进度达到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);
}
@测试
public void testSwingWorker()
{
SwingWorker worker=新SwingWorker(){
@凌驾
受保护的无效进程(列表块)
{
for(对象块:块)
{
System.out.println(“进程:+chunk.toString());
}
}
@凌驾
受保护的void done()
{
系统输出打印项次(“完成”);
}
@凌驾
受保护对象doInBackground()引发异常
{
//模拟长时间运行方法

对于(int i=0;i我对此进行了一些研究,下面是我的想法。我使用了一个
CountDownLatch
,基本上公开了它的
wait()
方法作为我的
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) {

        }
    }

}
final类Worker扩展SwingWorker{
专用最终倒计时闩锁实际完成倒数计时闩锁=新倒计时闩锁(1);
@凌驾
受保护的Void doInBackground()引发异常{
试一试{
System.out.println(“长任务启动”);
/*模拟长时间运行方法*/
对于(int i=0;i<100000000;i++){
双d=数学sqrt(i);
}
返回null;
}最后{
实际上,finishedlatch.countDown();
}
}
public void awaitActualCompletion()引发InterruptedException{
实际上是finishedlatch.await();
}
公共静态void main(字符串[]args){
工人=新工人();
worker.execute();
试一试{
时间单位。秒。睡眠(1);
}捕捉(中断异常e){
}
系统输出打印项次(“取消”);
worker.cancel(true);
试一试{
worker.get();
}捕获(取消异常e){
System.out.println(“正确抛出的CancellationException”);
}捕捉(中断异常e){
}捕获(执行例外){
}
System.out.println(“等待实际完成”);
试一试{
worker.awaittactualcompletion();
系统输出打印项次(“完成”);
}捕捉(中断异常e){
}
}
}

受Paul Blighting解决方案的启发,我对其进行了一些改进,使其成为一个类,您可以使用子类来获得所需的功能性:

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

}
class WaitingWorker扩展SwingWorker{
专用最终倒计时闩锁实际完成倒数计时闩锁=新倒计时闩锁(1);
/**
*重写此项以执行有用的操作
*/
受保护的抽象空操作();
@凌驾
受保护的最终T doInBackground()引发异常{
试一试{
返回性能操作();
}最后{
实际上,finishedlatch.countDown();
}
}
public void awaitActualCompletion()引发InterruptedException{
实际上是finishedlatch.await();
}
}

这两个想法都是我还没有考虑过的。我不喜欢使用progress,原因和你提到的一样——它需要轮询。我喜欢发布/处理的想法,但它将我想在任务实际完成时执行的逻辑与
SwingWorker
类本身结合起来。出于同样的原因,我很少使用progress使用
done()值,并通知已注册的侦听器后台任务已真正完成。这将逻辑与swing worker分离。这是真的,但侦听对象在此期间如何阻止,直到收到通知为止?我假设逻辑将在EDT上执行-这是使用发布/处理的优势-它跳过发布将后台线程中的数据清除到EDT。如果您需要一个单独的线程在完成时阻止,请注册一个侦听器,其中包含来自您自己答案的ConcountDownLatch。收到通知后,侦听器将触发倒计时闩锁,允许等待的线程继续。明白了。因为等待的线程是EDT,它可能是bl由于“取消…”对话框,您所说的侦听器将关闭该对话框,从而取消EDT。也就是说,如果
SwingWo