如何从CompletableFuture返回主线程

时间:2018-12-15 02:45:26

标签: java multithreading minecraft bukkit completable-future

我需要从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();
                });
            }
        }
    });
}

问题是...主线程ID是21,在函数registerPanels()的第一行中,我打印了Thread#currentThread#getId(),它打印了多个不同的数字,范围在{{1 }}和30。如果它在主线程上运行,它应该打印42,对吗?

编辑: 这是第一个运行异步方法的调用

21

这些方法最初是从这里调用的...

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); } 方法会运行 不过,起初,我需要先创建SQL数据库中的表,然后才能更改向其添加任何数据……这就是#addToPerm(String lobby)方法(在#addToPerm(String lobby)方法中)的作用。一旦创建了大厅,我就需要用数据来填充它,例如#calibrate。添加完所有数据后,我需要更新本地缓存hubDatabase#addToPermJoinTable()。加载完所有缓存后,我需要返回主线程并调用InventoryManager#updatePermIconCache()方法,因为该方法利用了线程不安全的API。我仍然对如何执行此操作感到困惑...

3 个答案:

答案 0 :(得分:0)

  

调用join()或get()仅阻塞运行CompletableFuture的线程

那么您正在通过 current 线程完成那个未来吗?然后不要这样做...确保在您调用了joinget的线程之外的线程上执行了所有异步操作,并完成了它们的未来。

答案 1 :(得分:0)

要返回到线程(主线程或非主线程,无所谓),该线程必须调用某种方法来等待给定的CompletableFuture。通过调用其方法get(),等待CompletableFuture完成。就是这样。

您担心“调用join()或get()只会阻塞CompletableFuture在其中运行的线程...”-仅当从从中调用的方法调用join()或get()时,才会发生这种情况CompletableFuture。不这样做,程序将挂起。只需启动所有CompletableFutures。然后才调用join()或get()。

由于updatePermIconCache方法(在打印时)在不同的线程上运行,因此,不会从主线程调用它。我们看不到主线程上的内容,因此无法为您提供适当的建议。

答案 2 :(得分:0)

从主类中调用要在其中实现多线程的服务方法。 CompletableFuture的get()方法将确保仅在执行所有线程之后,它将返回存在主线程的main方法,并且仅在get()方法返回后才执行。

//Create a list of CompletableFutures:
List<CompletableFuture> futures= new ArrayList<>();

//Add your futures in this arrayList as mentioned below :
futures.add(CompletableFuture.runAsync(() ->{   
        // your code
});

CompletableFuture<Void> allCfs=CompletableFuture.allOf(futures.toArray(new CompletableFuture[futures.size()]));

try 
{
allCfs.get();
} catch (InterruptedException | ExecutionException e) {
        log.error(e.getMessage());
} 

//Once this process will be completed, only then your main thread will get executed.

Main Thread()