I assume all the task will be timed out after 1000ms, but actually it doesn't. It prints like below, how does these happen.
future0
java.util.concurrent.TimeoutException
1010
future1
java.util.concurrent.TimeoutException
2014
future2
3015
future3
3015
future4
3016
future5
3016
future6
3016
future7
java.util.concurrent.TimeoutException
4020
future8
java.util.concurrent.TimeoutException
5021
future9
6018
public static void main(String[] args) throws ExecutionException, InterruptedException, TimeoutException {
int taskCount = 10;
long ts = System.currentTimeMillis();
List<CompletableFuture> list = new ArrayList<>();
for (int i = 0; i < taskCount; i++) {
CompletableFuture future = CompletableFuture.runAsync(new Runnable() {
@Override
public void run() {
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
});
list.add(future);
}
for (int i = 0; i < taskCount; i++) {
System.out.println("future" + i);
try {
list.get(i).get(1000, TimeUnit.MILLISECONDS);
} catch (Exception e) {
System.out.println(e);
} finally {
System.out.println(System.currentTimeMillis() - ts);
}
}
}
I assume when I call CompletableFuture.get(long timeout, TimeUnit unit), I can always get the result or a TimeoutException just in time
You are submitting tasks to the common
ForkJoinPool. A fork-join pool has a set level of parallelism that it tries to maintain. The common pool's default parallelism is based on the number of available processors. In your case, the parallelism is set to seven. Due to the way your tasks are implemented, however, the calls tosleepprevent the pool from spawning threads to maintain its parallelism. Thus, only seven of your tasks can run concurrently at any given time. In short, not all your tasks are starting at the same time.Additionally, you are calling
geton each future sequentially. While the main thread is blocked on a call toget, the started tasks continue to execute.You can see all this better if you include more information in your logs.
Note: Start and end times are in milliseconds. Values are relative to a constant origin time.
From those times you can see tasks 0-6 all start immediately, but tasks 7-9 do not start until after tasks 0-6 complete, three seconds later. Meanwhile, the
getcalls happen every second. They also block for a second, except for tasks 3-6, wheregetreturns immediately because the tasks are already complete.Here is the code that gave the above output.
Note: Code compiled and executed with Java 21.