Timeouts in Squirrel

Timeouts are important for programs that connect to external resources or that otherwise need to bound execution time. Implementing timeouts in Java is straightforward using the ExecutorService and Future classes.

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";
        };

        // Here we submit the task and get a Future object
        Future<String> future1 = executor.submit(task1);

        try {
            // We try to get the result, but with a timeout of 1 second
            String result = future1.get(1, TimeUnit.SECONDS);
            System.out.println(result);
        } catch (TimeoutException e) {
            System.out.println("timeout 1");
        } catch (InterruptedException | ExecutionException 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 (InterruptedException | ExecutionException 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 implementation:

  1. We use an ExecutorService to manage our tasks.
  2. Tasks are represented as Callable objects, which can return a result and throw exceptions.
  3. We submit tasks to the executor and receive Future objects, which represent the pending results of the tasks.
  4. We use the Future.get() method with a timeout to attempt to retrieve the result of each task.
  5. If the task doesn’t complete within the specified timeout, a TimeoutException is thrown.

This approach provides similar functionality to the original example, allowing us to bound the execution time of operations and handle timeouts gracefully.