Transforming ListenableScheduledFuture<Void> to ListenableFuture<SomethingElse>

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

  •  23-07-2023
  •  | 
  •  

Domanda

I would like to get your feedback on the following problem and the solution (potential).

Suppose there is a Runnable task that samples CPU usage and writes it to a CSV file. This task doesn't return any result. This needs to be scheduled to be executed periodically forever. If the user cancels the task, we close the file writer and CSV file can be downloaded by the user.

When you submit such a task to the ListeningScheduledExecutorService (as shown below), you get a ListenableScheduledFuture that represents the result of the task.

ListenableScheduledFuture<Void> future = (ListenableScheduledFuture<Void>) scheduledExecutorService
            .scheduleAtFixedRate(task, initialDelay, interval, timeUnit); 

We register a callback to the future so that when the task has been cancelled, the CSV file is ready for download: That is we need to transform ListenableScheduledFuture to ListenableScheduledFuture.

Function<Void, File> transformFunc = new Function<Void, File>()
{
    @Override
    public File apply(Void arg0)
    {
        return file;
    }
};

ListenableScheduledFuture<File> futureToListen = (ListenableScheduledFuture<File>) Futures.transform(future, transformFunc);

// register a callback to the ListenableScheduledFuture<File>
Futures.addCallback(futureToListen, callback, executorService);

Note: According to Guava API DOC1, cancelling futureToListen should result in our task getting canceled.

Questions:

  1. Because the task result is void, does it make sense to cast to ListenableScheduledFuture as shown above?

  2. Does it semantically make sense to transform the future of task that returns void to a future of some type?

  3. Is there a better and a more elegant solution? Would it be better to use Java8's CompletableFuture?

È stato utile?

Soluzione

transform is probably not going to do what you want. You mentioned that cancelling futureToListen will cancel future, and that's true. The problem is that the same is true of the reserve: When future is cancelled, so too will futureToListen be. That will mean that it never computes its result.

To solve this problem, you have a couple options:

  1. If you don't care about being able to cancel future, then change futureToListen to a SettableFuture. Then have whoever cancels future also call futureToListen.set(file).
  2. If you do care about being able to cancel future, then change futureToListen to an AbstractFuture that (a) exposes set() (so that you can do what I recommend in (1)) and (b) implements interruptTask() to call future.cancel().

There are other possible clever solutions that involve triggering the work whenever future completes unsuccessfully, but I'm not sure I recommend then. I personally feel a little nervous about using "Future was cancelled" as a signal for "work is successfully done." That's because the Future could also be cancelled by an executor shutdown, for example. (Another reason: You'd need to be careful to distinguish between "threw an exception during execution" and "was cancelled.") For this reason, my suggested solutions are set up to call set() directly rather than to trigger off any cancellation of the future.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top