В ожидании отмененного будущего фактически закончить

StackOverflow https://stackoverflow.com/questions/3522427

  •  29-09-2019
  •  | 
  •  

Вопрос

у меня есть 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 Swing, вам нужно будет использовать таймер, чтобы периодически проверять свойство 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. Ваш process Метод переопределения в Swingworker поднимает это специальное значение и скрывает сообщение «Отмена ...». Преимущество в этом заключается в том, что не требуется не требуется таймеры или таймеры. Пример кода показывает, что хотя done Вызывается, как только задача будет отменена, пара методов публикации/процесса все еще работает, даже когда задача отменена.

Вдохновленный решением Пола Благословения, я немного улучшил его, чтобы стать классом, вы можете подкласс, чтобы получить желаемую функциональность:

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