Согласно this, следующий фрагмент должен быть асинхронным.

Следовательно, вывод должен выглядеть так: TP1, TP2, TP3, http://openjdk.java.net/. .

Однако, когда я запускаю его, я получаю: TP1, TP2, http://openjdk.java.net/ , TP3.

Похоже, что sendAsync блокирует основной поток. Это не то, что я ожидал от метода Async.

Я делаю что-то неправильно?

 public static void main(String[] args) {

    HttpClient client = HttpClient.newHttpClient();

    System.out.println("TP1");

    HttpRequest request = HttpRequest.newBuilder()
            .uri(URI.create("http://openjdk.java.net/"))
            .build();

    System.out.println("TP2");

    client.sendAsync(request, HttpResponse.BodyHandlers.ofString())
            .thenApply(HttpResponse::uri)
            .thenAccept(System.out::println)
            .join();

    System.out.println("TP3");

}
1
Adrian Smith 21 Сен 2020 в 22:37

1 ответ

Лучший ответ

Объяснение

Вы вызываете join(), и он явно ожидает и блокирует, пока не завершится будущее.

Из CompletableFuture # join:

Возвращает значение результата при завершении или генерирует исключение (не отмеченное), если завершено в исключительных случаях. [...]

Хотя это не упоминается явно, но очевидно из названия (см. Thread # join , который " ожидает, пока этот поток умрет ". ), он может вернуть результат, только дождавшись вызова полный.

Метод очень похож на CompletableFuture # get, они различаются своим поведением в отношении исключительного завершения:

При необходимости ожидает завершения этого будущего, а затем возвращает его результат.


Решение

Поместите будущее в переменную и присоединитесь позже, когда действительно захотите его дождаться.

Например:

System.out.println("TP2");

var task = client.sendAsync(request, HttpResponse.BodyHandlers.ofString())
        .thenApply(HttpResponse::uri)
        .thenAccept(System.out::println);

System.out.println("TP3");

task.join(); // wait later

Или никогда не ждите этого. Тогда ваш основной поток может умереть раньше, но JVM завершит работу только после того, как все потоки, не являющиеся демонами, будут мертвы, а поток, используемый HttpClient для задачи async, не будет потоком демона.


Заметка

Кроме того, никогда не полагайтесь на порядок многопоточного выполнения.

Даже если вы не ошиблись бы, наблюдаемый вами порядок будет действительным многопоточным выполнением.

Помните, что планировщик ОС волен решать, в каком порядке он что выполняет - это может быть любой порядок.

3
Zabuzard 21 Сен 2020 в 19:49