To improve Java Future, Java 8 provides CompletableFuture which can execute some code whenever its ready. In this article, we’re gonna take a look at new Java 9 CompletableFuture API that supports delay and timeout.
I. Delay
static Executor delayedExecutor(long delay, TimeUnit unit); static Executor delayedExecutor(long delay, TimeUnit unit, Executor executor); |
– The first method, not specify Executor
, returns a new Executor
that submits a task to the default executor (general purpose pool ForkJoinPool.commonPool()
) after delay time.
– The second method, with an Executor
as parameter, returns a new Executor
that submits a task to that input executor after delay time.
Now see an example to illustrate how the method works. We have a CompletableFuture
that will delay its completion by 3 seconds. The code could be:
future.completeAsync(supplier, CompletableFuture.delayedExecutor(3, TimeUnit.SECONDS)) .thenAccept(result -> System.out.println("accept: " + result)); // other statements |
The program runs ‘other statements’ first. 3 seconds later, it call get()
method of supplier
and pass the result to thenAccept()
.
II. Timeout
1. orTimeout()
CompletableFuture<T> orTimeout(long timeout, TimeUnit unit); |
The method exceptionally completes current CompletableFuture
by throwing a TimeoutException
if not otherwise completed before the timeout.
For example, we have a doWork()
method that takes 5 seconds to return a CompletableFuture
. But we set TIMEOUT only 3 seconds.
// TIMEOUT = 3; // doWork() takes 5 seconds to finish CompletableFuture<String> future = doWork("JavaSampleApproach") .orTimeout(TIMEOUT, TimeUnit.SECONDS) .whenComplete((result, error) -> { if (error == null) { System.out.println("The result is: " + result); } else { System.out.println("Sorry, timeout in " + TIMEOUT + " seconds"); } }); |
Run the code above, we get result that prints out:
Sorry, timeout in 3 seconds
and throw a java.util.concurrent.TimeoutException
.
Java 9 new CompletableFuture API also gives us another method to handle the case when timeout: completeOnTimeout()
.
2. completeOnTimeout()
CompletableFuture<T> completeOnTimeout(T value, long timeout, TimeUnit unit); |
The method completes current CompletableFuture
by input value
if not otherwise completed before the timeout.
Like the example above, we have a doWork()
method that takes 5 seconds to return a CompletableFuture
. But we set TIMEOUT only 3 seconds. We also specify the string value JavaTechnology in case the time 3 seconds is out and doWork()
hasn’t done its operation yet.
// TIMEOUT = 3; // doWork() takes 5 seconds to finish CompletableFuture<String> future = doWork("JavaSampleApproach") .completeOnTimeout("JavaTechnology", TIMEOUT, TimeUnit.SECONDS) .whenComplete((result, error) -> { if (error == null) { System.out.println("The result is: " + result); } else { // this statement will never run. System.out.println("Sorry, timeout in " + TIMEOUT + " seconds."); } }); |
Run the code above, we get result that prints out:
The result is: JavaTechnology
III. SOURCE CODE
1. DelayedExecutorTest.java
package com.javasampleapproach.java9completablefuture; import java.util.concurrent.CompletableFuture; import java.util.concurrent.ExecutionException; import java.util.concurrent.TimeUnit; public class DelayedExecutorTest { public static void main(String[] args) throws InterruptedException, ExecutionException { CompletableFuture<String> future = new CompletableFuture<>(); future.completeAsync(() -> { try { System.out.println("inside future: processing data..."); return "grokonez.com"; } catch (Throwable e) { return "not detected"; } }, CompletableFuture.delayedExecutor(3, TimeUnit.SECONDS)) .thenAccept(result -> System.out.println("accept: " + result)); // other statements for (int i = 1; i <= 5; i++) { try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("running outside... " + i + " s"); } } } |
Result:
running outside... 1 s running outside... 2 s running outside... 3 s inside future: processing data... accept: grokonez.com running outside... 4 s running outside... 5 s |
2. OrTimeOutTest.java
package com.javasampleapproach.java9completablefuture; import java.util.concurrent.CompletableFuture; import java.util.concurrent.ExecutionException; import java.util.concurrent.TimeUnit; public class OrTimeOutTest { private static final int TIMEOUT = 3; public static void main(String[] args) throws InterruptedException, ExecutionException { CompletableFuture<String> future = doWork("JavaSampleApproach") .orTimeout(TIMEOUT, TimeUnit.SECONDS) .whenComplete((result, error) -> { if (error == null) { System.out.println("The result is: " + result); } else { System.out.println("Sorry, timeout in " + TIMEOUT + " seconds."); } }); String content; content = future.get(); System.out.println("Result >> " + content); } private static CompletableFuture<String> doWork(String s) { return CompletableFuture.supplyAsync(() -> { for (int i = 1; i <= 5; i++) { try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("running inside doWork()... " + i + " s"); } return s + ".com"; }); } } |
Result:
running inside doWork()... 1 s running inside doWork()... 2 s running inside doWork()... 3 s Sorry, timeout in 3 seconds. Exception in thread "main" java.util.concurrent.ExecutionException: java.util.concurrent.TimeoutException at java.base/java.util.concurrent.CompletableFuture.reportGet(CompletableFuture.java:395) at java.base/java.util.concurrent.CompletableFuture.get(CompletableFuture.java:1999) at com.javasampleapproach.java9completablefuture.OrTimeOutTest.main(OrTimeOutTest.java:26) Caused by: java.util.concurrent.TimeoutException at java.base/java.util.concurrent.CompletableFuture$Timeout.run(CompletableFuture.java:2792) at java.base/java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:514) at java.base/java.util.concurrent.FutureTask.run(FutureTask.java:264) at java.base/java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:299) at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1161) at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:635) at java.base/java.lang.Thread.run(Thread.java:844) |
If we change TIMEOUT to 6
running inside doWork()... 1 s running inside doWork()... 2 s running inside doWork()... 3 s running inside doWork()... 4 s running inside doWork()... 5 s The result is: grokonez.com Result >> grokonez.com |
3. CompleteOnTimeoutTest.java
package com.javasampleapproach.java9completablefuture; import java.util.concurrent.CompletableFuture; import java.util.concurrent.ExecutionException; import java.util.concurrent.TimeUnit; public class CompleteOnTimeoutTest { private static final int TIMEOUT = 3; public static void main(String[] args) throws InterruptedException, ExecutionException { CompletableFuture<String> future = doWork("JavaSampleApproach") .completeOnTimeout("JavaTechnology", TIMEOUT, TimeUnit.SECONDS).whenComplete((result, error) -> { if (error == null) { System.out.println("The result is: " + result); } else { // this statement will never run. System.out.println("Sorry, timeout in " + TIMEOUT + " seconds."); } }); String content = future.get(); System.out.println("Result >> " + content); } private static CompletableFuture<String> doWork(String s) { return CompletableFuture.supplyAsync(() -> { for (int i = 1; i <= 5; i++) { try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("running inside doWork()... " + i + " s"); } return s + ".com"; }); } } |
Result:
running inside doWork()... 1 s running inside doWork()... 2 s running inside doWork()... 3 s The result is: JavaTechnology Result >> JavaTechnology |
If we change TIMEOUT to 6
running inside doWork()... 1 s running inside doWork()... 2 s running inside doWork()... 3 s running inside doWork()... 4 s running inside doWork()... 5 s The result is: grokonez.com Result >> grokonez.com |
Last updated on September 11, 2018.
fzqncluvgusmvxwickuqeazofqzfzk