6

SwingWorkerスレッドの中断をチェックしないコードを呼び出す があります。の呼び出し後worker.cancel(true)worker.get()メソッドはすぐにスローCancellationExceptionします (想定どおり)。ただし、バックグラウンド タスクのコードは、そのスレッドが中断されるかどうかを決してチェックしないため、喜んで実行を継続します。

バックグラウンド タスクが実際に終了するまで待機する標準的な方法はありますか? 「キャンセル中...」メッセージまたはそのようなものを表示して、タスクが終了するまでブロックしたいと考えています。(必要に応じて、他の解決策を探すだけで、ワーカー クラスのフラグを使用して常にこれを達成できると確信しています。)

4

3 に答える 3

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) {

        }
    }

}
于 2010-08-19T17:25:08.923 に答える
1

これを行うための標準的な、または既製の方法に最も近いのは、progressによって提供されるプロパティおよび/またはパブリッシュ/プロセス メソッドのペアSwingWorkerです。バックグラウンド作業が完了したことを示すために、メソッドの最後でこれを「I'm finished」値に設定できます。Swing ワーカーで待機しているスレッドは、「キャンセル中...」メッセージを表示し、進行状況を定期的にチェックして、完了したかどうかを確認できます。待機中のスレッドが Swing EDT の場合は、Timer を使用して進行状況プロパティを定期的にチェックし、完了したらキャンセル メッセージをクリアする必要があります。

以下は、頑固なバックグラウンド スレッドを実行するサンプル コードです。このスレッドはキャンセルされ、進行状況が 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);
}

もう 1 つの方法は、メソッドのペアを使用しpublish\processて、バックグラウンド スレッドが終了したことを示す特別な値を EDT にプッシュすることです。次に、 SwingWorker のprocessオーバーライド メソッドがこの特別な値を取得し、「キャンセル中...」メッセージを非表示にします。これの利点は、ポーリングやタイマーが必要ないことです。コード例はdone、タスクがキャンセルされるとすぐに呼び出されますが、タスクがキャンセルされた場合でもパブリッシュ/プロセス メソッドのペアが機能することを示しています。

于 2010-08-19T15:03:30.533 に答える
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();
    }

}
于 2011-06-16T17:37:46.290 に答える