我需要从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。我仍然对如何执行此操作感到困惑...
答案 0 :(得分:0)
调用join()或get()仅阻塞运行CompletableFuture的线程
那么您正在通过 current 线程完成那个未来吗?然后不要这样做...确保在您调用了join
或get
的线程之外的线程上执行了所有异步操作,并完成了它们的未来。
答案 1 :(得分:0)
您担心“调用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()