Прерывание метода чтения с будущим и завершаемым будущим - PullRequest
0 голосов
/ 28 февраля 2020

При решении задачи я заметил поведение, которое не могу объяснить.

Моя задача состояла в том, чтобы прочитать из InputStream и прервать это чтение после истечения времени ожидания. Хотя многие люди говорят, что блокирование чтения не может быть прервано, я достиг этой цели с помощью 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();
   }
}

Но когда я реализую то же самое с помощью Future, я вижу, что TimeoutException было брошен в JVM, но я все еще вижу, что поток чтения не был прерван и все еще работает .

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();
   }
}

Почему такая разница? Я считаю, что CompletableFuture не делает никаких магов c

1 Ответ

1 голос
/ 29 февраля 2020

Ни один из ваших фрагментов кода не остановит поток "чтения", когда вы достигнете future.get(5, TimeUnit.SECONDS);. Они будут продолжать ждать вашего ввода от System.in. Если вы хотите остановить его, вы должны отправить прерывание этому потоку и надеяться, что поток отреагирует на него. Или, очевидно, вы можете принудительно уничтожить поток.

Однако вызовы CompletableFuture.runAsync() и Executors.newSingleThreadExecutor() используют разные потоки, особенно с использованием различных флагов daemon (см. Что такое поток демона в Java? ). Когда вы поместите System.out.println(Thread.currentThread().isDaemon()); в свой метод doRead(), вы увидите, что CompletableFuture.runAsync использует поток демона (поэтому он не блокирует завершение JVM), где Executors.newSingleThreadExecutor() нет (и поддерживает JVM).

...