Timeouts in Mercury
Timeouts are important for programs that connect to external resources or that otherwise need to bound execution time. Implementing timeouts in Java is possible using the java.util.concurrent
package, specifically with ExecutorService
, Future
, and TimeUnit
.
import java.util.concurrent.*;
public class Timeouts {
public static void main(String[] args) {
ExecutorService executor = Executors.newFixedThreadPool(2);
// For our example, suppose we're executing an external
// call that returns its result after 2s. We use a Callable
// to represent this operation.
Callable<String> task1 = () -> {
Thread.sleep(2000);
return "result 1";
};
Future<String> future1 = executor.submit(task1);
try {
// Here we implement a timeout. We try to get the result,
// but if it takes more than 1 second, a TimeoutException
// is thrown.
String result = future1.get(1, TimeUnit.SECONDS);
System.out.println(result);
} catch (TimeoutException e) {
System.out.println("timeout 1");
} catch (Exception e) {
e.printStackTrace();
}
// If we allow a longer timeout of 3s, then the task
// will complete and we'll print the result.
Callable<String> task2 = () -> {
Thread.sleep(2000);
return "result 2";
};
Future<String> future2 = executor.submit(task2);
try {
String result = future2.get(3, TimeUnit.SECONDS);
System.out.println(result);
} catch (TimeoutException e) {
System.out.println("timeout 2");
} catch (Exception e) {
e.printStackTrace();
}
executor.shutdown();
}
}
Running this program shows the first operation timing out and the second succeeding.
$ javac Timeouts.java
$ java Timeouts
timeout 1
result 2
In this Java version, we use ExecutorService
to manage our tasks, Callable
to represent our operations, and Future
to handle the results. The get
method of Future
allows us to specify a timeout, which throws a TimeoutException
if the operation takes too long.
This approach provides similar functionality to the original example, allowing us to bound the execution time of operations and handle timeouts gracefully.