簡體   English   中英

等待取消的未來實際完成

[英]Waiting for a cancelled future to actually finish

我有一個SwingWorker調用一些不檢查線程中斷的代碼。 在調用worker.cancel(true)worker.get()方法將立即拋出CancellationException (正如它應該的那樣)。 但是,由於后台任務的代碼從不檢查其線程是否被中斷,因此它很樂意繼續執行。

是否存在等待后台任務實際完成的標准方法? 我希望顯示一個“正在取消...”消息或類似的東西,並阻止任務終止。 (我確信如果有必要,我可以在工人類中使用標志來完成此操作,只需查找其他任何解決方案。)

我玩了一下這個,這就是我想出來的。 我正在使用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) {

        }
    }

}

與標准或現成方法最接近的是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解決方案的啟發,我將它改進了一點,成為一個類,你可以通過子類來獲得所需的功能:

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

}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM