Last active
April 24, 2025 18:01
-
-
Save CattenLinger/3b2fbcbea7b3e3eaf4dbc2b8ba841596 to your computer and use it in GitHub Desktop.
To concurrently get only the fastest result with CompletableFuture in Java.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| import java.util.Random; | |
| import java.util.concurrent.*; | |
| public class FastestResultPlayground { | |
| static void sleep(long millis) { | |
| try { | |
| // Simulating a heavy job | |
| Thread.sleep(millis); | |
| } catch (Exception e) { | |
| throw new RuntimeException(e); | |
| } | |
| } | |
| static final Random random = new Random(); | |
| // By default JVM uses ForkJoinPool to do async jobs. | |
| // This settings is optional | |
| static final ExecutorService executor = ForkJoinPool.commonPool(); | |
| static CompletableFuture<String> createDemoJob(int index, CompletableFuture<String> yield) { | |
| return CompletableFuture.supplyAsync(() -> { | |
| final long ms = random.nextInt(10_000); | |
| System.out.println("Created job " + index + " Sleep " + ms + " @T:" + Thread.currentThread().getName()); | |
| sleep(ms); | |
| return String.valueOf(index); | |
| }, executor).whenComplete((result, ex) -> { // i: Chain calling returns different Future instance. | |
| // Completed Future will returns 'false', Future.isDone() is not necessary | |
| if (yield.complete(result)) return; | |
| System.out.println("Job Canceled. @T:" + Thread.currentThread().getName()); | |
| }); | |
| } | |
| public static void main(String[] args) throws ExecutionException, InterruptedException { | |
| final CompletableFuture<String> firstSucceedFuture = new CompletableFuture<>(); | |
| // You can create only 1 job to see what will happend. | |
| final CompletableFuture<Void> allCompletedFuture = CompletableFuture.allOf( | |
| createDemoJob(0, firstSucceedFuture), | |
| createDemoJob(1, firstSucceedFuture), | |
| createDemoJob(2, firstSucceedFuture) | |
| ).whenComplete((result, ex) -> { | |
| if(firstSucceedFuture.isDone()) return; | |
| // No job result. returns an error. | |
| System.out.println("No job succeeded. @T:" + Thread.currentThread().getName()); | |
| firstSucceedFuture.completeExceptionally(new Exception("Failed")); | |
| }); | |
| System.out.println("Wait for fastest job result... @T:" + Thread.currentThread().getName()); | |
| System.out.println("First job finished is: " + firstSucceedFuture.get()); | |
| System.out.println("Cancel other jobs... @T:" + Thread.currentThread().getName()); | |
| allCompletedFuture.cancel(true); | |
| /* | |
| Output result example: | |
| Created job 0 Sleep 9966 @T:ForkJoinPool.commonPool-worker-3 | |
| Created job 2 Sleep 7072 @T:ForkJoinPool.commonPool-worker-7 | |
| Created job 1 Sleep 6026 @T:ForkJoinPool.commonPool-worker-5 | |
| Wait for fastest job result... @T:main | |
| First job finished is: 1 | |
| Cancel other jobs... @T:main | |
| */ | |
| } | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment