1

While solving the task, I've noticed a behavior I can not explain.

My task was to read from InputStream and interrupt that reading after a timeout. Even though lots of people say blocking read can not be interrupted, I've achieved that goal using CompletableFuture

public void startReader() {
   CompletableFuture<Void> future = CompletableFuture.runAsync(() -> doRead(System.in));
   future.get(5, TimeUnit.SECONDS);
}

private void doRead(InputStream in) {
   try {
      new BufferedReader(new InputStreamReader(in)).readLine();
   } catch (IOException e) {
      e.printStackTrace();
   }
}

But when I implement the same using Future, I can see TimeoutException been thrown into JVM, but I still can see that reading thread was not terminated and still running.

public void startReader() throws ExecutionException, InterruptedException, TimeoutException {
   Future<?> future = Executors.newSingleThreadExecutor().submit(() -> doRead(System.in));
   future.get(5, TimeUnit.SECONDS);
}

private void doRead(InputStream in) {
   try {
      new BufferedReader(new InputStreamReader(in)).readLine();
   } catch (IOException e) {
      e.printStackTrace();
   }
}

Why there is such a difference? I believe CompletableFuture does not make any magic

a3dsfcv
  • 1,146
  • 2
  • 20
  • 35

1 Answers1

1

Neither of your code snippets will stop the "reading" thread when you reached the future.get(5, TimeUnit.SECONDS);. They will continue waiting for your input from System.in. If you want to stop it you should send an interrupt to that thread and hope the thread react on it. Or you can force kill the thread, obviously.

However, the CompletableFuture.runAsync() and Executors.newSingleThreadExecutor() calls use different threads, specially using different daemon flags (see What is a daemon thread in Java?). When you place a System.out.println(Thread.currentThread().isDaemon()); inside your doRead() method you will see that CompletableFuture.runAsync uses a daemon thread (so it doesn't block the JVM from terminating) where Executors.newSingleThreadExecutor() does not (and keeps the JVM alive).

Progman
  • 16,827
  • 6
  • 33
  • 48