Nowadays you can use
try {
String s = CompletableFuture.supplyAsync(() -> br.readLine())
.get(1, TimeUnit.SECONDS);
} catch (TimeoutException e) {
System.out.println("Time out has occurred");
} catch (InterruptedException | ExecutionException e) {
// Handle
}
EDIT: poseidon correctly points out that in the event of a timeout, the above approach does not interrupt the underlying Thread that is processing the Future's task. Without an interrupt, the underlying Thread will continue to process the Future's task to completion, with no way of knowing that the result is no longer wanted. With an interrupt, the underlying Thread can at least see (if it checks) that it has been interrupted, allowing it to gracefully conclude processing and exit.
For methods in the JDK that do blocking IO, by convention they are implemented such that they check the calling Thread's interrupt status (and throw an InterruptedException if it is true). So, interrupting a Thread can allow it to quickly exit even out of potentially-infinite wait situations, like reading from an input source.
Without further exposition, if we want to interrupt the underlying Thread on timeout, we can adjust:
Future<String> future = CompletableFuture.supplyAsync(() -> br.readLine());
try {
String s = future.get(1, TimeUnit.SECONDS);
} catch (TimeoutException e) {
System.out.println("Time out has occurred");
future.cancel(true);
} catch (InterruptedException | ExecutionException e) {
// Handle
}