Java 可从内部完成未来注射

Java 可从内部完成未来注射,java,asynchronous,concurrency,java-8,future,Java,Asynchronous,Concurrency,Java 8,Future,是否可以从内部在CompletableFuture链中注入CompletableFuture 我使用的函数如下: public CompletableFuture<Boolean> getFutureOfMyLongRunningTask() { CompletableFuture<Boolean> future = CompletableFuture.supplyAsync(() -> { // ... Some processing he

是否可以从内部在
CompletableFuture
链中注入
CompletableFuture

我使用的函数如下:

public CompletableFuture<Boolean> getFutureOfMyLongRunningTask() {
    CompletableFuture<Boolean> future = CompletableFuture.supplyAsync(() -> {
        // ... Some processing here ...
        if (somecondition failed)
            return false; // Task failed!

        return true; // OK
    }).thenApplyAsync((Boolean result) -> {
        if (!result) // check of previous stage fail
            return false;

        // ... Some processing here ...

        if (!some condition satisfied) {
            // This is where I want the injection to happen. 
            // This stage should be suspended and a new stage should be injected between this point and the next stage.
        }

        return true; // OK
    }).thenApplyAsync((Boolean result) -> {
        if (!result) // check of previous stage fail
            return false;

        // ... Some processing here ...

        return true; // OK
    });

    // This is the result we have to wait for.
    return future;
}
并将未来注入链条。这将使调用线程“自由”地执行其他事情,而不是坐等结果


我不知道我是否能说得更清楚,但让我们遵循这个例子

我在主线程中运行一个循环:

for (int i = 0; i < 1000; i++) {
    getFutureOfMyLongRunningTask(i);
}
for(int i=0;i<1000;i++){
getFutureOfMyLongRunningTask(i);
}
此循环仅存在于主线程上,但每次对函数的调用都会将一个新任务排入线程池p。现在假设P是大小为1的固定线程池。这意味着P中只存在一个线程,它只能处理1任务。然而,主循环将使所有1000个任务排队。然后,主循环将需要等待所有任务完成

现在假设1000中的1st任务需要执行长数据库查询。我们现在有两个选择:

  • 查询在处理线程(属于线程池p)内执行sync。这意味着我只需在
    if(!满足某些条件)
    块中发出查询,然后等待结果。这会有效地阻止任务处理,因为线程池P没有空闲线程。唯一一个在IO上被阻塞

  • 查询在处理线程(属于线程池p)内执行async。这意味着如果(!满足某些条件)块,我将在
    块内发出查询,并立即返回我将侦听的未来(DB驱动程序可能会生成另一个线程并阻止该线程等待结果)。但是,属于P的线程现在可以自由处理至少另一个任务

  • 在我看来,选项2优于选项1,同样的推理也适用于大小为>1或动态大小的线程池

    我想要的就是尽可能地保持线程池的空闲,以产生最少数量的线程,从而避免浪费资源


    希望这是有意义的。如果没有,请您解释一下我的错误在哪里?

    不要使用
    然后应用同步
    ,而是使用
    然后合成
    然后合成同步
    ,这样函数就可以返回一个
    可完成的未来
    而不是
    Foo
    。如果
    出现某种情况,则可以使用
    而不是
    返回true
    满足后,您需要
    返回CompletableFuture.completedFuture(true)

    public CompletableFuture getFutureOfMyLongRunningTask(){
    CompletableFuture=CompletableFuture.SupplySync(()->{
    //…这里有些处理。。。
    如果(某些条件失败)
    返回false;//任务失败!
    返回true;//确定
    }).ThenComposeSync((布尔结果)->{
    if(!result)//前级检查失败
    返回CompletableFuture.completedFuture(false);
    //…这里有些处理。。。
    如果(!满足某些条件){
    返回runSomeOtherQuery()
    }
    返回CompletableFuture.completedFuture(true);//确定
    }).ThenApplySync((布尔结果)->{
    if(!result)//前级检查失败
    返回false;
    //…这里有些处理。。。
    返回true;//确定
    });
    //这是我们必须等待的结果。
    回归未来;
    }
    公共CompletableFuture runSomeOtherQuery(){
    ....
    }
    
    您似乎认为在链接的阶段之间拆分工作(涉及“异步”)会神奇地为您的程序逻辑增加并发性改进

    当您链接阶段时,您正在创建一个直接的、连续的依赖项,即使您使用“异步”之一方法,因为后续从属阶段的执行不会在前一个阶段完成之前开始。因此,这种链接增加了昂贵的线程跳转的机会,即不同的线程执行下一个阶段,但不会提高并发性,因为仍然最多有一个线程处理一个阶段。实际实际上,仍然可能的情况是,同一个线程碰巧执行所有阶段,这可能是最快的执行

    有一种更简单、更自然的方式来表达依赖关系。只需在一段代码中一个接一个地编写操作。您仍然可以将该代码块安排为异步执行。因此,如果您的起点是

    public CompletableFuture<Boolean> getFutureOfMyLongRunningTask() {
        CompletableFuture<Boolean> future = CompletableFuture.supplyAsync(() -> {
            // First stage processing here ...
            if (somecondition failed)
                return false; // Task failed!
    
            return true; // OK
        }).thenApplyAsync((Boolean result) -> {
            if (!result) // check of previous stage fail
                return false;
    
            // Second stage processing here ...
    
            if (!some condition satisfied) {
                // This is where I want the injection to happen. 
                // This stage should be suspended and a new stage should be
                // injected between this point and the next stage.
            }
    
            return true; // OK
        }).thenApplyAsync((Boolean result) -> {
            if (!result) // check of previous stage fail
                return false;
    
            // Third stage processing here ...
    
            return true; // OK
        });
    
        // This is the result we have to wait for.
        return future;
    }
    
    public CompletableFuture getFutureOfMyLongRunningTask(){
    CompletableFuture=CompletableFuture.SupplySync(()->{
    //这里的第一阶段处理。。。
    如果(某些条件失败)
    返回false;//任务失败!
    返回true;//确定
    }).ThenApplySync((布尔结果)->{
    if(!result)//前级检查失败
    返回false;
    //这里的第二阶段处理。。。
    如果(!满足某些条件){
    //这就是我想要注射的地方。
    //这一阶段应该暂停,新的阶段应该结束
    //在这一点和下一阶段之间注入。
    }
    返回true;//确定
    }).ThenApplySync((布尔结果)->{
    if(!result)//前级检查失败
    返回false;
    //第三阶段处理在这里。。。
    返回true;//确定
    });
    //这是我们必须等待的结果。
    回归未来;
    }
    
    把它改成

    public CompletableFuture<Boolean> getFutureOfMyLongRunningTask() {
        CompletableFuture<Boolean> future = CompletableFuture.supplyAsync(() -> {
            // First stage processing here ...
            if (somecondition failed)
                return false; // Task failed!
            // Second stage processing here ...
    
            if (!some condition satisfied) {
                // alternative "injected" stage processing
                if(injected stage failed)
                    return false;
            }
            // Third stage processing here ...
    
            return true; // OK
        });
    
        // This is the result we have to wait for.
        return future;
    }
    
    public CompletableFuture getFutureOfMyLongRunningTask(){
    CompletableFuture=CompletableFuture.SupplySync(()->{
    //第一阶段
    
    public CompletableFuture<Boolean> getFutureOfMyLongRunningTask() {
        CompletableFuture<Boolean> future = CompletableFuture.supplyAsync(() -> {
            // First stage processing here ...
            if (somecondition failed)
                return false; // Task failed!
    
            return true; // OK
        }).thenApplyAsync((Boolean result) -> {
            if (!result) // check of previous stage fail
                return false;
    
            // Second stage processing here ...
    
            if (!some condition satisfied) {
                // This is where I want the injection to happen. 
                // This stage should be suspended and a new stage should be
                // injected between this point and the next stage.
            }
    
            return true; // OK
        }).thenApplyAsync((Boolean result) -> {
            if (!result) // check of previous stage fail
                return false;
    
            // Third stage processing here ...
    
            return true; // OK
        });
    
        // This is the result we have to wait for.
        return future;
    }
    
    public CompletableFuture<Boolean> getFutureOfMyLongRunningTask() {
        CompletableFuture<Boolean> future = CompletableFuture.supplyAsync(() -> {
            // First stage processing here ...
            if (somecondition failed)
                return false; // Task failed!
            // Second stage processing here ...
    
            if (!some condition satisfied) {
                // alternative "injected" stage processing
                if(injected stage failed)
                    return false;
            }
            // Third stage processing here ...
    
            return true; // OK
        });
    
        // This is the result we have to wait for.
        return future;
    }