Использование поставщика в CompletableFuture дает другой результат, чем использование лямбда
Я создал небольшой пример чтения текстового файла и заключил вызов в CompletableFuture
,
public class Async {
public static void main(String[] args) throws Exception {
CompletableFuture<String> result = ReadFileUsingLambda(Paths.get("path/to/file"));
result.whenComplete((ok, ex) -> {
if (ex == null) {
System.out.println(ok);
} else {
ex.printStackTrace();
}
});
}
public static CompletableFuture<String> ReadFileUsingSupplier(Path file) throws Exception {
return CompletableFuture.supplyAsync(new Supplier<String>() {
@Override
public String get() {
try {
return new String(Files.readAllBytes(file));
} catch (IOException e) {
e.printStackTrace();
return "test";
}
}
}, ForkJoinPool.commonPool());
}
public static CompletableFuture<String> ReadFileUsingLambda(Path file) throws Exception {
return CompletableFuture.supplyAsync(() -> {
try {
return new String(Files.readAllBytes(file));
} catch (IOException e) {
e.printStackTrace();
return "test";
}
} , ForkJoinPool.commonPool());
}
}
Этот код ничего не возвращает. Выполняется и "ничего не происходит", без ошибок или вывода. Если я позвоню ReadFileUsingSupplier
вместо ReadFileUsingLambda
тогда я получаю содержимое файла, напечатанное в консоли!
Для меня это не имеет смысла, потому что лямбда-это сокращение для написания встроенной функции, и это не должно изменить поведение, но в этом примере это очевидно.
2 ответа
Я думаю, что это просто вопрос времени выполнения - лямбда может занять немного больше времени для выполнения, что позволит программе завершиться до того, как вы закончите читать файл.
Попробуй это:
- добавить
Thread.sleep(1000);
как первый оператор в блоке try вReadFileUsingSupplier
и вы не увидите никакого выхода - добавить
Thread.sleep(1000);
в конце вашего основного при использованииReadFileUsingLambda
и вы увидите ожидаемый результат
Чтобы убедиться, что ваш основной не выйдет до завершения будущего, вы можете позвонить:
result.join();
Как уже отмечалось, в любом случае вы должны использовать result.join(), чтобы избежать слишком быстрого выхода из основного потока.
Кажется, есть штраф за использование лямбда-выражений против анонимных замыканий, когда JVM нагревается, после чего производительность остается той же. Я нашел эту информацию в другом SO-потоке, который, в свою очередь, связывает исследование производительности с Oracle.
Как sidenote, Thread.sleep () не очень хорошая идея, когда-либо исправлять странные проблемы с синхронизацией. Выяснение причины и применение соответствующих мер будет намного понятнее, если вы перечитываете вас или других, например,
System.out.println(result.get(5, TimeUnit.SECONDS));
Это также позволяет отказаться от.join ().