Как мне вернуться к основному потоку из CompletableFuture - PullRequest
0 голосов
/ 15 декабря 2018

Мне нужно вернуться к основному потоку из CompletableFuture<Void>.

У меня есть сеть CompletableFuture, которая выполняет асинхронную обработку данных, полученных и вставленных в базу данных SQL.Как только все это будет выполнено, я хочу вернуться в основной поток и выполнить функцию, и я не нашел разумного способа сделать это.

Вызов join() или get() блокирует только тот поток, которыйCompletableFuture работает ... Я не хочу постоянно опрашивать isDone().

Я пытался использовать whenComplete(), но, похоже, он не работает должным образом ...

public static void updatePermIconCache() {
    Logger.debug("thread1: " + Thread.currentThread().getId());
    hubDatabase.getLobbies().thenAccept(s -> {
        for (String lobby : s) {
            for (int i = 0; i < 27; i++) {
                final int x = i;
                hubDatabase.isInPermTable(lobby, i).thenAccept(b -> {
                    if (!b) return;
                    hubDatabase.cachePermToJoinTable(lobby, x);
                });
            }
        }
    }).whenComplete((v, t) -> registerPanels());
}

Я хочу, чтобы моя функция registerPanels() была вызвана в главном потоке, но, учитывая, что даже функция updatePermIconCache() называется асинхронной, наряду с другими функциями, которые определяют, будет ли эта функция вызываться илинет, я не понимаю, как, ну, вернуть его в основной поток.

РЕДАКТИРОВАТЬ: изменен код на это ...

public static void updatePermIconCache() {
    Logger.debug("thread1: " + Thread.currentThread().getId());
    hubDatabase.getLobbies().thenAccept(s -> {
        for (String lobby : s) {
            for (int i = 0; i < 27; i++) {
                final int x = i;
                hubDatabase.isInPermTable(lobby, i).thenAccept(b -> {
                    if (!b) return;
                    hubDatabase.cachePermToJoinTable(lobby, x).join();
                    registerPanels();
                });
            }
        }
    });
}

Проблема в ... идентификатор основного потокаравно 21, в первой строке функции registerPanels() я печатаю Thread#currentThread#getId(), и он печатает несколько разных чисел, в диапазоне от 30 до 42.Он должен печатать 21, если он запускается в главном потоке, верно?

EDIT: это первый вызываемый метод, который запускается async

public CompletableFuture<Void> calibrate() {
    return CompletableFuture.runAsync(() -> {
        getLobbies().thenAccept(a -> Arrays.stream(a).forEach(this::createPermToJoinTable));
        getLobbies().thenAccept(a -> Arrays.stream(a).forEach(this::createVanishedTable));
    });
}

public CompletableFuture<String[]> getLobbies() {
    String sql = "SELECT * FROM lobby";
    List<String> list = new ArrayList<>();
    return queryAsync(r -> {
        while(r.next()) {
            list.add(r.getString(1));
        }
        return r;
    }, sql).thenApplyAsync(v -> list.toArray(new String[list.size()]));
}

Эти методы изначально вызываются отсюда ...

public static CompletableFuture<Void> addToPerm(String lobby) {
    HubDatabase hubDatabase = MinelightHub.getHubDatabase();
    return hubDatabase.calibrate().thenRunAsync(() -> {
        hubDatabase.addToPermToJoinTable(lobby, 0, "Admin", getDesc(true), Material.WOOL, getData(DyeColor.RED), Permissions.ADMIN, true);
        hubDatabase.addToPermToJoinTable(lobby, 1, "Mod", getDesc(false), Material.WOOL, getData(DyeColor.ORANGE), Permissions.MOD, false);
        hubDatabase.addToPermToJoinTable(lobby, 2, "Builder", getDesc(false), Material.WOOL, getData(DyeColor.CYAN), Permissions.BUILDER, false);
        hubDatabase.addToPermToJoinTable(lobby, 3, "YouTube", getDesc(false), Material.WOOL, getData(DyeColor.RED), Permissions.YOUTUBE, false);
        hubDatabase.addToPermToJoinTable(lobby, 9, "JrAdmin", getDesc(false), Material.WOOL, getData(DyeColor.RED), Permissions.JRADMIN, false);
        hubDatabase.addToPermToJoinTable(lobby, 10, "JrMod", getDesc(false), Material.WOOL, getData(DyeColor.ORANGE), Permissions.JRMOD, false);
        hubDatabase.addToPermToJoinTable(lobby, 11, "Artist", getDesc(false), Material.WOOL, getData(DyeColor.CYAN), Permissions.ARTIST, false);
        hubDatabase.addToPermToJoinTable(lobby, 12, "Twitch", getDesc(false), Material.WOOL, getData(DyeColor.PURPLE), Permissions.TWITCH, false);
        hubDatabase.addToPermToJoinTable(lobby, 17, "Default", getDesc(false), Material.WOOL, getData(DyeColor.GRAY), Permissions.DEFAULT, false);
        hubDatabase.addToPermToJoinTable(lobby, 18, "SrMod", getDesc(false), Material.WOOL, getData(DyeColor.ORANGE), Permissions.SRMOD, false);
        hubDatabase.addToPermToJoinTable(lobby, 19, "Trial", getDesc(false), Material.WOOL, getData(DyeColor.ORANGE), Permissions.TRIAL, false);
        hubDatabase.addToPermToJoinTable(lobby, 20, "Partner", getDesc(false), Material.WOOL, getData(DyeColor.BLUE), Permissions.PARTNER, false);
        hubDatabase.addToPermToJoinTable(lobby, 21, "VIP", getDesc(false), Material.WOOL, getData(DyeColor.GREEN), Permissions.VIP, false);
    }).thenRunAsync(InventoryManager::updatePermIconCache);
}

Теперь вы можетевид пути, который необходим, чтобы помочь информировать об этой ситуации.Когда я создаю 'лобби', сначала запускается метод #addToPerm(String lobby), хотя таблицы в базе данных SQL необходимо создать, прежде чем я смогу изменить, добавить в него какие-либо данные ... Это то, что (в методе #addToPerm(String lobby))) метод #calibrate делает.Как только он создал лобби, мне нужно заполнить его данными, такими как hubDatabase#addToPermJoinTable().После добавления всех этих данных мне нужно обновить локальный кеш InventoryManager#updatePermIconCache().После загрузки всего этого кэша мне нужно вернуться в основной поток и вызвать метод #registerPanels(), так как этот метод использует небезопасный API потока.Я все еще застрял на том, как это сделать ...

Ответы [ 2 ]

0 голосов
/ 15 декабря 2018

чтобы вернуться к потоку (основному или не основному, не имеет значения), этот поток должен вызвать некоторый метод, который ожидает заданного CompletableFuture.Ожидание CompletableFuture осуществляется путем вызова его метода get () .Вот и все.

Вы боитесь, что «Вызов join () или get () блокирует только поток, в котором выполняется CompletableFuture ...» - это может произойти, только когда join () или get ()вызывается из метода, вызываемого из CompletableFuture.Не делайте этого, программа зависнет.Просто запустите все ваши CompletableFutures.и только затем вызовите join () или get ().

Поскольку (как он напечатан) метод updatePermIconCache выполняется в разных потоках, это означает, что он не вызывается из основного потока.Мы не видим, что вызывается в главном потоке, и поэтому не можем дать вам правильный совет.

0 голосов
/ 15 декабря 2018

Вызов join () или get () блокирует только поток, в котором запущено CompletableFuture

Итак, вы завершаете это будущее из потока current ?Тогда не делайте этого ... убедитесь, что все ваши асинхронные операции выполнены и их будущее завершено в потоках, отличных от потока, который вы называете join или get in.

...