By using futures, you would get this type of functionality "for free":

```java

Future<Object> future = executorService.submit(new Callable<Object>() {
  public Object run() throws Exception {
    stage.process(doc);
    return null; // We need Callable to be able to throw checked exceptions, but then we need to return something.
  }
}

try {
    future.get(timeout, TimeOut.MILLISECONDS);
} catch ( TimeoutException e ) {
    // Decide what to do here. Throwing ProcessException might not be the correct solution considering comment above.
} catch ( ExecutionException e ) {
    throw e.getCause(); // Throw the exception thrown by stage.process(doc)
}
```

This code is from memory, so may not work "as-is", but the pattern is valid. To get an executorService, I would consider simply doing `Executors.newFixedThreadPool(1)`, in other words, there is a single thread available for processing. Otherwise, you will need to consider thread safety, or create a Stage instance per future.