24

I am confused with the following.

I know, if I use the schedule method from the ScheduledThreadPoolExecutor class:

ScheduledFuture<?> scheduledFuture = 
scheduledThreadPoolExecutor.schedule(myClassRunnable, 5, TimeUnit.SECONDS);

I am able to retrieve later the value through scheduledFuture.get(5, TimeUnit.SECONDS) or scheduledFuture.get() and it should be null because the task has been executed just only once and it is completed. And null because I am working with the Runnable schedule method version and not with the Callable schedule method version. It according with the API.

Until here I am fine.

My question:

What is the purpose of ScheduledFuture if is retrieved from the scheduleWithFixedDelay (even from scheduleAtFixedRate) method:

ScheduledFuture<?> scheduledFuture= 
scheduledThreadPoolExecutor.scheduleWithFixedDelay(myClassRunnable, 1, 5, TimeUnit.SECONDS);

Yes, I know both fixed methods execute the same task many times until the ScheduledThreadPoolExecutor's shutdown method is called (it must stop all the tasks scheduled).

I did a research through Google looking for some examples using ScheduledFuture returned from scheduleWithFixedDelay, I only found one using the cancel method, to cancel a specific task. But none working with get().

I don't know if I am wrong, but seems useless the get() method if we are working with scheduleWithFixedDelay, because if I use later:

  • scheduledFuture.get() - it remains awaiting and the Runnable object remains working many times (run,complete,delay,run,etc... )
  • scheduledFuture.get(32, TimeUnit.SECONDS) - always gives a TimeoutException

I thought I should be able to retrieve the null value since I can use the period argument/parameter from the scheduleWithFixedDelay method. I.e: Run the Runnable object, wait until it completes and use the scheduledFuture.get() to get the null value that confirms it has been completed, await the period of the delay time to run again the Runnable object according with the period value etc....

Clarifications and examples are totally welcome.

Steve Chambers
  • 37,270
  • 24
  • 156
  • 208
Manuel Jordan
  • 15,253
  • 21
  • 95
  • 158

5 Answers5

7

ScheduledFuture can be used to get time left before next task execution:

    ScheduledFuture<?> f = Executors.newScheduledThreadPool(1).scheduleAtFixedRate(new Runnable() {
        public void run() {
            System.out.println("run");
        }
    }, 0, 10000, TimeUnit.MILLISECONDS);
    Thread.sleep(1000);
    System.out.println("Time left before next run " + f.getDelay(TimeUnit.MILLISECONDS));

prints

run
Time left before next run 8999
Evgeniy Dorofeev
  • 133,369
  • 30
  • 199
  • 275
  • Thanks by the reply and code, ok has sense, just curious if you have a case where the ScheduledFuture's **get** method would be used with scheduleAtFixedRate/scheduleWithFixedDelay. Thank You. – Manuel Jordan Jul 31 '14 at 13:10
  • 24
    Does not really answer to the OP question `What is the purpose of ScheduledFuture.get() method` – Nicolas Labrot Mar 19 '18 at 11:00
2

I tried this out with the following code:

ScheduledExecutorService scheduler = Executors.newSingleThreadScheduledExecutor();
AtomicInteger count = new AtomicInteger(0);
Runnable task = () -> {
    int currentCount = count.incrementAndGet();
    System.out.println("Task #" + currentCount + " started");
    if (currentCount == 2) {
        System.out.println("Shutting down scheduler...");
        scheduler.shutdown();
    }
    try {
        Thread.sleep(1000);
    } catch (InterruptedException ie) {
        throw new RuntimeException(ie);
    }
    System.out.println("Task #" + currentCount + " finished");
};

System.out.println("Starting scheduler...");
ScheduledFuture<?> scheduledFuture = scheduler.scheduleWithFixedDelay(
    task, 0, 2, TimeUnit.SECONDS);
System.out.println("Getting scheduled future...");
System.out.println(scheduledFuture.get());        
System.out.println("End of code reached.");

Here is the output:

Exception in thread "main" java.util.concurrent.CancellationException
    at java.base/java.util.concurrent.FutureTask.report(FutureTask.java:121)
    at java.base/java.util.concurrent.FutureTask.get(FutureTask.java:191)
    at Rextester.main(source.java:33)
Starting scheduler...
Getting scheduled future...
Task #1 started
Task #1 finished
Task #2 started
Shutting down scheduler...
Task #2 finished

Online Rextester Demo: https://rextester.com/LYKN32123

Not sure how useful this is but it shows the get() method throws a CancellationException if the scheduler is shut down.

Steve Chambers
  • 37,270
  • 24
  • 156
  • 208
1

I would think that in the case of using .scheduleWithFixedDelay(...) (or scheduleAtFixedRate(...)), the get() method of the returned ScheduledFuture<?> feels indeed as an odd fit.

I believe you won't ever receive anything from the get() method, just expect an exception to be thrown from it, when Runnable is cancelled.

Surely one can see a use-case for this ;-)

see JavaDoc

https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/ScheduledExecutorService.html#scheduleAtFixedRate-java.lang.Runnable-long-long-java.util.concurrent.TimeUnit-

Returns: a ScheduledFuture representing pending completion of the task, and whose get() method will throw an exception upon cancellation

Julien
  • 1,765
  • 20
  • 26
1

You can't catch the exception thrown by the submitted task without calling get.

Suppose you have a task like this.

public class Task1 implements Runnable {
    private int counter = 3;

    @Override
    public void run() {
        System.out.println("It is called");
        counter--;
        if (counter == 0) {
            throw new RuntimeException(new Exception("It fails"));
        }
    }
}

No exception is thrown by the following code, so you are not able to handle that.

public static void main(String[] args) throws Exception {
    ScheduledExecutorService executorService = Executors.newScheduledThreadPool(1);
    Task1 task1 = new Task1();
    executorService.scheduleAtFixedRate(task1, 0, 2, TimeUnit.SECONDS);
}

However, if you add get to it, then you can catch the exception.

public static void main(String[] args) throws Exception {
    ScheduledExecutorService executorService = Executors.newScheduledThreadPool(1);
    Task1 task1 = new Task1();
    ScheduledFuture<?> future = executorService.scheduleAtFixedRate(task1, 0, 2, TimeUnit.SECONDS);

    try {
        future.get();  // CAUTION: This line blocks the execution
    } catch (ExecutionException e) {
        e.printStackTrace();
        executorService.shutdown();
    }
}
Franz Wong
  • 1,024
  • 1
  • 10
  • 32
-1

Using scheduledFuture.get() you can get a handle to the task, and in case this task needs to be cancelled say manually from the UserInterface or based on some conditions like the null, the handle can be used to cancel it.

randeepsp
  • 3,572
  • 9
  • 33
  • 40