Проблема CompletableFuture с UUID.randomUUID () - PullRequest
0 голосов
/ 24 января 2019

Поэтому я решил начать использовать CompletableFuture в Java8, и я не могу понять, что не так с этим фрагментом:

public static void main(String...strings) throws Exception {
    final Supplier<User> makeUserSupplier = () -> makeUser();
    final Supplier<String> uuidSupplier =  () -> makeUUID();

    final CompletableFuture<User> futureUser = CompletableFuture.supplyAsync(makeUserSupplier);
    final CompletableFuture<String> futureUUID = CompletableFuture.supplyAsync(uuidSupplier);

    CompletableFuture.allOf(futureUser, futureUUID)
        .thenApplyAsync(aVoid -> {
            final User user = futureUser.join();
            final String uuid = futureUUID.join();
            return "received user + " + user + " and uuid is " + uuid ;
        })
        .handle((ok, e) -> {
            System.out.println("ok----" + ok);
            System.out.println("e----" + e);
            return null;
        });
}
    private static User makeUser() throws RuntimeException {
//        throw new RuntimeException("lkj");
        return new User(1L, "mm", "ll", "kk");
    }
    private static String makeUUID() throws RuntimeException {
        return UUID.randomUUID().toString();
//        return "dummy";
    }

где класс User определяется как:

@Data
@AllArgsConstructor
public class User {
    private Long id;
    private String username;
    private String password;
    private String role;
}

Я получаю такое поведение:

  • Ничего не печатается в моей консоли, когда я использую UUID.randomUUID().toString(), и я получаю результат, когда использую какой-то случайный String.
  • Последней точкой останова, которую я могу достичь при отладке, является строка, когда я присоединяюсь к futureUUID final String uuid = futureUUID.join();, а затем моя программа останавливается без результата.

Может кто-нибудь попытаться объяснить мне, почему я получаю это странное поведение при использовании UUID?

PS: я только начал изучать CompletableFuture и думал о параллельных фьючерсах, потом случайно пришел к этому.

С уважением.

1 Ответ

0 голосов
/ 24 января 2019

Это не имеет ничего общего с UUID, за исключением того, что его генерация занимает некоторое время, и вы не ожидаете завершения.

Поскольку все операции выполняются в фоновых потоках, а вы возвращаетесь из *При использовании метода 1003 * JVM определит, что поток, не являющийся демоном, больше не работает, и завершит работу.

Просто добавьте операцию ожидания завершения:

final Supplier<User> makeUserSupplier = () -> makeUser();
final Supplier<String> uuidSupplier =  () -> makeUUID();

final CompletableFuture<User> futureUser = CompletableFuture.supplyAsync(makeUserSupplier);
final CompletableFuture<String> futureUUID = CompletableFuture.supplyAsync(uuidSupplier);

CompletableFuture.allOf(futureUser, futureUUID)
    .thenApplyAsync(aVoid -> {
        final User user = futureUser.join();
        final String uuid = futureUUID.join();
        return "received user + " + user + " and uuid is " + uuid ;
    })
    .handle((ok, e) -> {
        System.out.println("ok----" + ok);
        System.out.println("e----" + e);
        return null;
    })
    .join(); // wait for completion

Обратите внимание, что в исходном файлекод, вы использовали .allOf(futureUser, futureUser) вместо .allOf(futureUser, futureUUID), поэтому цепная операция может выполняться, когда futureUUID еще не завершена, что может привести к блокировке рабочего потока в вызове futureUUID.join().

Ваш код был бы намного проще, если бы вы использовали

final CompletableFuture<User> futureUser = CompletableFuture.supplyAsync(() -> makeUser());
final CompletableFuture<String> futureUUID = CompletableFuture.supplyAsync(() -> makeUUID());

futureUser.thenCombineAsync(futureUUID, (user, uuid) -> {
        return "received user + " + user + " and uuid is " + uuid;
    })
    .handle((ok, e) -> {
        System.out.println("ok----" + ok);
        System.out.println("e----" + e);
        return null;
    })
    .join(); // wait for completion

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

...