Search code examples
javafutureswingworker

Waiting for a cancelled future to actually finish


I have a SwingWorker which calls some code that does not check for thread interruption. After the call to worker.cancel(true), the worker.get() method will throw CancellationException immediately (as it is supposed to). However, since the background task's code never checks for its thread to be interrupted, it happily continues executing.

Is there a standard way to wait for the background task to actually finish? I'm looking to show a "Cancelling..." message or something of the sort and block until the task has terminated. (I'm sure I could always accomplish this with a flag in the worker class if necessary, just looking for any other solutions.)


Solution

  • I played around with this a bit and here's what I came up with. I'm using a CountDownLatch and basically exposing its await() method as a method on my SwingWorker object. Still looking for any better solutions.

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