【问题标题】:Wait for a CompletableFuture to be complete, then return a different value?等待 CompletableFuture 完成,然后返回不同的值?
【发布时间】:2019-05-14 04:30:37
【问题描述】:

我有一个CompletableFuture<Void>,它调用了一个我无法更改其返回类型的异步方法,或者关于它的任何事情。

我想等待这个方法完成(我手动完成),然后返回一个String值,我该怎么做?

public String getServer(Player p) {
    FutureServer f = new FutureServer(CompletableFuture.runAsync(() -> {
        sendUTF(p, "GetServer");
        try {
            Thread.sleep(10000); //so the future doesnt complete itself
        } catch (Exception e) {
            e.printStackTrace();
        }
    }), p.getUniqueId().toString());
    serverSet.add(f);
    String server = "";

    //server isn't final so I can't use it in the lambda
    f.getFutureVoid().whenComplete(v -> server = f.getServer()); 

    return server;
}

public class FutureServer {

    private CompletableFuture<Void> futureVoid;
    private String s;
    private String uuid;

    public FutureServer(CompletableFuture<Void> futureVoid, String uuid) {
        this.futureVoid = futureVoid;
        this.uuid = uuid;
    }

    public String getUuid() {
        return uuid;
    }

    public CompletableFuture<Void> getFutureVoid() {
        return futureVoid;
    }

    public boolean hasServer() {
        return s != null;
    }

    public void setServer(String s) {
        this.s = s;
    }

    public String getServer() {
        return s;
    }
}

我想将字符串设置为等于FutureServer#getServer()(自己的方法),但我需要等到CompletableFuture&lt;Void&gt; 完成。我该怎么办?

这是被称为异步且不可更改的方法...我使用的异步调用此其他方法的方法是sendUTF()

@Override
public void onPluginMessageReceived(String s, Player p, byte[] bytes) {
    if (!s.equals("BungeeCord")) return;

    ByteArrayDataInput in = ByteStreams.newDataInput(bytes);
    String subChannel = in.readUTF();

    switch(subChannel) {
        case "GetServer":
            String server = in.readUTF();
            serverSet.stream().filter(f -> f.getUuid().equals(p.getUniqueId().toString())).findFirst().ifPresent(f -> {
                f.setServer(server); //getting the string I need and placing it into this object
                f.getFutureVoid().complete(null); //completing the void future manually
            });
            break;
    }

}

【问题讨论】:

  • 那么使用CompletableFuture&lt;Void&gt; 是必须的吗?
  • 无论如何,如果您的getServer() 方法必须返回String,那么它所做的一切都必须是非异步的。即使它所做的事情是异步的,它也必须等待最终结果才能使该方法返回正确的值,因此它必须等待(调用线程将被阻塞)。正确的方法是让这个方法返回某种Future
  • 我知道,我可以让主线程等待,我只想知道如何获取值
  • 如果调用线程在检索结果时被阻塞,那么以非异步方式完成所有这些操作会简单得多。只有当您需要做某事但无法等待结果时,异步方法才有意义,这样您希望在结果可用时收到通知,然后您会返回检索结果。
  • 阅读帖子,它已完成异步,我无法更改它

标签: java asynchronous completable-future


【解决方案1】:

最简单的解决方案是在那个未来向join() 发送,或者使用:

public String getServer(Player p) {
    FutureServer f = new FutureServer(CompletableFuture.runAsync(() -> {
        sendUTF(p, "GetServer");
        try {
            Thread.sleep(10000); //so the future doesnt complete itself
        } catch (Exception e) {
            e.printStackTrace();
        }
    }), p.getUniqueId().toString());
    serverSet.add(f);

    return f.getFutureVoid().thenApply(v -> f.getServer()).join(); 
}

可以很容易地转换为返回CompletableFuture&lt;String&gt;,而不是通过删除.join(),或者:

public String getServer(Player p) {
    FutureServer f = new FutureServer(CompletableFuture.runAsync(() -> {
        sendUTF(p, "GetServer");
        try {
            Thread.sleep(10000); //so the future doesnt complete itself
        } catch (Exception e) {
            e.printStackTrace();
        }
    }), p.getUniqueId().toString());
    serverSet.add(f);

    f.getFutureVoid().join();
    return f.getServer();
}

【讨论】:

    【解决方案2】:

    你可以这样做:

    final AtomicReference<String> server = new AtomicReference<>("");
    
    f.getFutureVoid().whenComplete(v -> server.set(f.getServer())).get(/* maybe add a timeout */); 
    
    return server.get();
    

    【讨论】:

    • 我试试,使用这种方法有什么缺点吗?
    • 调用 getServer() 的线程将一直阻塞,直到未来完成——但我想你期待吗?
    猜你喜欢
    • 1970-01-01
    • 2019-08-01
    • 1970-01-01
    • 2016-09-15
    • 2021-11-13
    • 2018-11-08
    • 2016-09-10
    • 2021-06-02
    • 1970-01-01
    相关资源
    最近更新 更多