Abdul D.
—In Java, you may run into a java.util.concurrent.TimeoutException
error when using the java.util.concurrent
package:
Task timed out: null java.util.concurrent.TimeoutException at java.base/java.util.concurrent.FutureTask.get(FutureTask.java:204) at TimeoutExceptionExample.main(TimeoutExceptionExample.java:17)
You can resolve a java.util.concurrent.TimeoutException
error by ensuring the task causing the error does not exceed its timeout limit or by returning a default value when the limit is reached.
The TimeoutException
indicates that the error was thrown by the get
method of FutureTask
. Specifically, it was thrown by the overloaded version of the get
method that accepts a timeout parameter, as shown in the following line from the stack trace:
at java.base/java.util.concurrent.FutureTask.get(FutureTask.java:204)
This design ensures that the task can be controlled and prevented from blocking indefinitely. However, if the specified timeout is too short or the task encounters delays, a TimeoutException
error occurs.
Let’s use the following example to reproduce and resolve the issue:
import java.util.concurrent.*; public class TimeoutExceptionExample { public static void main(String[] args) { ExecutorService executorService = Executors.newSingleThreadExecutor(); Future<Integer> future = executorService.submit(() -> { int sum = 0; for (int i = 1; i <= 1000; i++) { // Add numbers from 1 to 1000 Thread.sleep(1); // Simulate a delay for each addition sum += i; } return sum; }); try { Integer result = future.get(1, TimeUnit.SECONDS); System.out.println("Sum: " + result); } catch (TimeoutException e) { e.printStackTrace(); } catch (Exception e) { e.printStackTrace(); } finally { executorService.shutdown(); } } }
This code calculates the sum of numbers from 1 to 1000. It simulates a delay for each addition, which causes the task to exceed the timeout limit.
First things first: Get rid of any inefficiencies.
The delay in the loop (Thread.sleep(1)
) causes the task to take longer than expected. Remove the delay to optimize the code:
import java.util.concurrent.*; public class OptimizedTimeoutExample { public static void main(String[] args) { ExecutorService executorService = Executors.newSingleThreadExecutor(); Future<Integer> future = executorService.submit(() -> { int sum = 0; for (int i = 1; i <= 1000; i++) { sum += i; // Perform addition without delay. } return sum; }); try { Integer result = future.get(1, TimeUnit.SECONDS); System.out.println("Sum: " + result); } catch (TimeoutException e) { System.err.println("Task timed out: " + e.getMessage()); e.printStackTrace(); } catch (Exception e) { e.printStackTrace(); } finally { executorService.shutdown(); } } }
This prints:
Sum: 500500
When optimization isn’t an option, give the task more time to complete:
import java.util.concurrent.*; public class TimeoutExceptionExample { public static void main(String[] args) { ExecutorService executorService = Executors.newSingleThreadExecutor(); Future<Integer> future = executorService.submit(() -> { int sum = 0; for (int i = 1; i <= 1000; i++) { sum += i; Thread.sleep(1); } return sum; }); try { Integer result = future.get(3, TimeUnit.SECONDS); // Extend the timeout limit to 3 seconds System.out.println("Sum: " + result); } catch (TimeoutException e) { System.err.println("Task timed out: " + e.getMessage()); e.printStackTrace(); } catch (Exception e) { e.printStackTrace(); } finally { executorService.shutdown(); } } }
This prints:
Sum: 500500
If extending the timeout still doesn’t work, you can use a fallback mechanism to handle the error.
This example returns a default value when the task times out:
import java.util.concurrent.*; public class FallbackTimeoutExample { public static void main(String[] args) { ExecutorService executorService = Executors.newSingleThreadExecutor(); Future<Integer> future = executorService.submit(() -> { int sum = 0; for (int i = 1; i <= 1000000; i++) { try { Thread.sleep(1); } catch (InterruptedException e) { Thread.currentThread().interrupt(); } sum += i; } return sum; }); try { Integer result = future.get(1, TimeUnit.SECONDS); System.out.println("Sum: " + result); } catch (TimeoutException e) { System.err.println("Task timed out. Returning default value."); System.out.println("Sum: 0 (Default value)"); } catch (Exception e) { e.printStackTrace(); } finally { executorService.shutdown(); } } }
This prints:
Fallback: Task timed out. Returning default value. Sum: 0 (Default value)
Let’s get fancy and use the CompletableFuture
method to define a default value in case of a timeout:
import java.util.concurrent.*; public class CompletableFutureExample { public static void main(String[] args) { // This runs the task asynchronously. CompletableFuture<Integer> future = CompletableFuture.supplyAsync(() -> { int sum = 0; for (int i = 1; i <= 1000000; i++) { sum += i; try { Thread.sleep(1); // Simulate a delay } catch (InterruptedException e) { Thread.currentThread().interrupt(); } } return sum; }); // If the task does not complete within 1 second, return the default value 1784293664. Integer result = future.completeOnTimeout(1784293664, 1, TimeUnit.SECONDS).join(); System.out.println("Sum: " + result); } }
This prints:
Sum: 1784293664
The Future
interface provides two versions of the get
method:
get()
waits indefinitely for the task to complete.get(long timeout, TimeUnit unit)
waits up to the specified timeout for the task to complete, throwing a TimeoutException
if the timeout is exceeded.While using the parameterless get()
avoids the TimeoutException` error, it can result in the program waiting indefinitely, which is not ideal.
Future
documentationCompletableFuture
class documentationTasty treats for web developers brought to you by Sentry. Get tips and tricks from Wes Bos and Scott Tolinski.
SEE EPISODESConsidered “not bad” by 4 million developers and more than 100,000 organizations worldwide, Sentry provides code-level observability to many of the world’s best-known companies like Disney, Peloton, Cloudflare, Eventbrite, Slack, Supercell, and Rockstar Games. Each month we process billions of exceptions from the most popular products on the internet.
Here’s a quick look at how Sentry handles your personal information (PII).
×We collect PII about people browsing our website, users of the Sentry service, prospective customers, and people who otherwise interact with us.
What if my PII is included in data sent to Sentry by a Sentry customer (e.g., someone using Sentry to monitor their app)? In this case you have to contact the Sentry customer (e.g., the maker of the app). We do not control the data that is sent to us through the Sentry service for the purposes of application monitoring.
Am I included?We may disclose your PII to the following type of recipients:
You may have the following rights related to your PII:
If you have any questions or concerns about your privacy at Sentry, please email us at compliance@sentry.io.
If you are a California resident, see our Supplemental notice.