В ожидании отмененного будущего фактически закончить
-
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();
}
}