When Java operations hit their time limits, they throw java.util.concurrent.TimeoutException
. This checked exception appears in scenarios ranging from thread synchronization barriers that never complete to Selenium tests waiting for elements that never appear.
The challenge isn't just catching these exceptions—it's designing your code to handle timing constraints intelligently.
Since java.util.concurrent.TimeoutException
is a checked exception, it must be explicitly handled in methods which can throw this exception - either by using a try-catch block or by throwing it using the throws
clause.
What Causes java.util.concurrent.TimeoutException
Blocking operations in Java that have a specified timeout require a way to indicate that the timeout has occurred. For many such operations, it is possible to return a value that indicates timeout. When this is not possible or desirable, TimeoutException
should be thrown.
The most common scenarios where you'll encounter TimeoutException include:
- Thread Synchronization: Operations like
CyclicBarrier.await()
orCountDownLatch.await()
that wait for other threads to complete within a specified time limit. - Selenium WebDriver Operations: WebDriverWait operations that time out while waiting for elements to appear, become clickable, or meet certain conditions on a web page.
- Connection Pool Management: Database or HTTP connection pools that cannot provide a connection within the configured lease timeout period.
- Future Operations:
Future.get()
calls with timeout parameters that expire before the background task completes.
java.util.concurrent.TimeoutException Example
Here is an example of a TimeoutException
thrown when a thread awaits at a barrier until the specified timeout elapses:
import java.util.concurrent.BrokenBarrierException;
import java.util.concurrent.CyclicBarrier;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
class TimeoutExceptionExample {
public static void main(String args[]) throws TimeoutException, InterruptedException, BrokenBarrierException {
CyclicBarrier barrier = new CyclicBarrier(2);
barrier.await(10, TimeUnit.MILLISECONDS);
}
}
In the above example, the main thread invokes the await()
method on an instance of CyclicBarrier
with a specified timeout of 10 milliseconds. When the barrier is not reached by other threads within the specified timeout, a TimeoutException
is thrown:
Exception in thread "main" java.util.concurrent.TimeoutException
at java.base/java.util.concurrent.CyclicBarrier.dowait(CyclicBarrier.java:257)
at java.base/java.util.concurrent.CyclicBarrier.await(CyclicBarrier.java:435)
at TimeoutExceptionExample.main(TimeoutExceptionExample.java:9)
Here's another common example with Selenium WebDriver:
import org.openqa.selenium.By;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.chrome.ChromeDriver;
import org.openqa.selenium.support.ui.WebDriverWait;
import org.openqa.selenium.support.ui.ExpectedConditions;
import java.time.Duration;
import java.util.concurrent.TimeoutException;
public class SeleniumTimeoutExample {
public static void main(String[] args) {
WebDriver driver = new ChromeDriver();
WebDriverWait wait = new WebDriverWait(driver, Duration.ofSeconds(5));
try {
driver.get("https://example.com");
// This will throw TimeoutException if element doesn't appear within 5 seconds
wait.until(ExpectedConditions.presenceOfElementLocated(By.id("nonexistent-element")));
} catch (org.openqa.selenium.TimeoutException e) {
// Note: Selenium wraps java.util.concurrent.TimeoutException
System.out.println("Element not found within timeout period");
} finally {
driver.quit();
}
}
}
When the element with ID "nonexistent-element" is not found within the 5-second timeout period, Selenium throws a TimeoutException
that contains the underlying java.util.concurrent.TimeoutException
:
Exception in thread "main" org.openqa.selenium.TimeoutException:
Expected condition failed: waiting for presence of element located by: By.id: nonexistent-element
(tried for 5 second(s) with 500 milliseconds interval)
Build info: version: '4.15.0', revision: '1d14b5521b'
System info: os.name: 'Windows 10', os.arch: 'amd64', os.version: '10.0', java.version: '11.0.16'
Driver info: org.openqa.selenium.chrome.ChromeDriver
Capabilities {acceptInsecureCerts: false, browserName: chrome, browserVersion: 118.0.5993.89, ...}
at org.openqa.selenium.support.ui.WebDriverWait.timeoutException(WebDriverWait.java:95)
at org.openqa.selenium.support.ui.FluentWait.until(FluentWait.java:230)
at SeleniumTimeoutExample.main(SeleniumTimeoutExample.java:16)
Caused by: java.util.concurrent.TimeoutException
at java.base/java.util.concurrent.FutureTask.get(FutureTask.java:204)
at org.openqa.selenium.support.ui.FluentWait.until(FluentWait.java:208)
How to Avoid java.util.concurrent.TimeoutException
Rather than simply avoiding the exception, the key is handling timeout scenarios gracefully. Here are proven strategies:
1. Configure Appropriate Timeout Values
Set realistic timeout values based on your application's performance characteristics and user expectations:
// Too short - likely to cause unnecessary timeouts
WebDriverWait shortWait = new WebDriverWait(driver, Duration.ofSeconds(1));
// More reasonable for web elements
WebDriverWait reasonableWait = new WebDriverWait(driver, Duration.ofSeconds(10));
// For slower operations like page loads
WebDriverWait longWait = new WebDriverWait(driver, Duration.ofSeconds(30));
2. Implement Retry Logic with Backoff
For operations that might succeed on retry, implement intelligent retry mechanisms:
public boolean waitForElementWithRetry(WebDriver driver, By locator, int maxAttempts) {
for (int attempt = 1; attempt <= maxAttempts; attempt++) {
try {
WebDriverWait wait = new WebDriverWait(driver, Duration.ofSeconds(5));
wait.until(ExpectedConditions.presenceOfElementLocated(locator));
return true;
} catch (org.openqa.selenium.TimeoutException e) {
if (attempt == maxAttempts) {
System.out.println("Element not found after " + maxAttempts + " attempts");
return false;
}
// Wait before retrying (exponential backoff)
try {
Thread.sleep(1000 * attempt);
} catch (InterruptedException ie) {
Thread.currentThread().interrupt();
return false;
}
}
}
return false;
}
3. Use Timeout-Aware Exception Handling
Design your exception handling to provide meaningful feedback and fallback behavior:
public void performOperationWithTimeout() {
try {
Future<String> future = executorService.submit(() -> {
// Some long-running operation
return "Result";
});
String result = future.get(10, TimeUnit.SECONDS);
System.out.println("Operation completed: " + result);
} catch (TimeoutException e) {
System.out.println("Operation timed out - continuing with default behavior");
// Implement fallback logic here
handleTimeout();
} catch (InterruptedException | ExecutionException e) {
System.out.println("Operation failed: " + e.getMessage());
}
}
private void handleTimeout() {
// Fallback behavior when timeout occurs
System.out.println("Using cached result or default values");
}
4. Monitor and Adjust Connection Pool Settings
For connection-related timeouts, tune your connection pool configuration:
// Example with HikariCP
HikariConfig config = new HikariConfig();
config.setConnectionTimeout(30000); // 30 seconds
config.setLeakDetectionThreshold(60000); // 60 seconds
config.setMaxLifetime(1800000); // 30 minutes
config.setMaximumPoolSize(20);
Best Practices for Timeout Handling
- Set Realistic Timeouts: Base timeout values on actual performance metrics, not arbitrary numbers. Monitor your application to understand typical operation durations.
- Log Timeout Events: Always log timeout occurrences with sufficient context for debugging. Include operation details, timeout duration, and system state.
- Graceful Degradation: Design your application to continue functioning even when certain operations timeout, providing alternative paths or cached results when possible.
lip>Implement Circuit Breakers: For external service calls, use circuit breaker patterns to prevent cascading failures when timeouts become frequent.
The TimeoutException
isn't always something to avoid—sometimes it's the appropriate way to handle operations that take too long. The key is anticipating these scenarios and handling them gracefully in your application design.
Track, Analyze and Manage Errors With Rollbar
Managing errors and exceptions in your code is challenging. It can make deploying production code an unnerving experience. Being able to track, analyze, and manage errors in real-time can help you to proceed with more confidence. Rollbar automates error monitoring and triaging, making fixing Java errors easier than ever. Try it today!