質問

私は持っています SwingWorker スレッドの中断をチェックしないコードを呼び出します。通話後 worker.cancel(true), 、 worker.get() メソッドがスローします CancellationException すぐに(想定されるように)。ただし、バックグラウンドタスクのコードがスレッドを中断することをチェックしないため、喜んで実行され続けます。

バックグラウンドタスクを待つ標準的な方法はありますか 実際に 終了?タスクが終了するまで、「キャンセル...」メッセージまたはソートとブロックの何かを表示したいと考えています。 (必要に応じて、必要に応じてワーカークラスのフラグでこれを常に達成できると確信しています。他のソリューションを探しています。)

役に立ちましたか?

解決

私はこれを少し遊んでいましたが、これが私が思いついたものです。私はaを使用しています 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) {

        }
    }

}

他のヒント

これを行う標準的な、または既製の方法に最も近いものは progress プロパティおよび/またはによって提供されるパブリッシュ/プロセスメソッドペア SwingWorker. 。これをメソッドの最後に「私は完成した」値に設定して、背景作業が完了したことを示します。スイングワーカーを待っているスレッドは、「キャンセル...」メッセージを出し、定期的に進捗を確認して、完了に達したかどうかを確認できます。待っているスレッドがスイングEDTである場合、タイマーを使用して、進行状況プロパティを定期的に確認し、完了したときにキャンセルメッセージをクリアする必要があります。

頑固なバックグラウンドスレッドを実行するコードの例は、キャンセルされ、進行状況が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に終了したことを示す特別な値を押すためのペア。あなたの process スイングワーカーのオーバーライドメソッドは、この特別な価値を取り上げ、「キャンセル...」メッセージを隠します。これの利点は、投票やタイマーが必要ないことです。例のコードは、それを示しています 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帰属
所属していません StackOverflow
scroll top