标签: completable-future

CompletionStage是否总是在CompletionException中包装异常?

CompletionStage的Javadoc指出:

[...]如果一个阶段的计算突然以(未经检查的)异常或错误终止,那么所有需要完成的依赖阶段也会异常完成,并且CompletionException将异常作为其原因.

看作异常完成总是包含异常,CompletionException为什么这样做exceptionally(),whenComplete()handle()代表异常Throwable代替CompletionException

这很重要,因为它可以防止人们直接在这些方法中重新抛出异常.

这些方法是否有可能接收除以外的异常CompletionException或者我可以安全地强制演员到这种类型吗?

(我在本地运行了一些测试,以及挖掘CompletableFuture源代码,乍一看,我没有看到如何抛出任何其他类型的异常.)

java completable-future

16
推荐指数
1
解决办法
2389
查看次数

仅在达到条件时才链接多个CompletionStage

我有几种CompletionStage方法可以链接.问题是第一个的结果将决定是否应该执行下一个.现在,实现这一目标的唯一方法似乎是将"特殊"参数传递给next,CompletionStage因此它不会执行完整的代码.例如:

public enum SomeResult {
    RESULT_1,
    RESULT_2,
    RESULT_3
}

public CompletionStage<SomeResult> someMethod(SomeArgument someArgument) {

    return CompletableFuture.supplyAsync(() -> {
        // loooooong operation
        if (someCondition)
            return validValue;
        else
            return null;
    }).thenCompose(result -> {
        if (result != null)
            return someMethodThatReturnsACompletionStage(result);
        else
            return CompletableFuture.completedFuture(null);
    }).thenApply(result -> {
        if (result == null)
            return ChainingResult.RESULT_1;
        else if (result.someCondition())
            return ChainingResult.RESULT_2;
        else
            return ChainingResult.RESULT_3;
    });
}
Run Code Online (Sandbox Code Playgroud)

因为整个代码依赖于第一个代码someCondition(如果它是false结果将是RESULT_1,如果不是那么整个代码应该被执行)这个结构对我来说看起来有点难看.有没有办法决定是否应该执行2nd(thenCompose(...))和3rd(thenApply(...))方法?

java-8 completable-future

15
推荐指数
1
解决办法
1万
查看次数

与CompletableFuture的Spring @Async

我对这段代码有疑问:

@Async
public CompletableFuture<String> doFoo() {
    CompletableFuture<String> fooFuture = new CompletableFuture<>();  

    try {
        String fooResult = longOp();
        fooFuture.complete(fooResult);
    } catch (Exception e) {
        fooFuture.completeExceptionally(e);
    }

    return fooFuture;
}
Run Code Online (Sandbox Code Playgroud)

问题是:doFoo仅在longOp完成后(正确或异常)返回fooFuture,因此返回已经完成的期货,或者Spring在执行主体之前做了一些魔法并返回?如果代码在longOp()上被阻塞,你会如何表达计算被送到执行程序?

也许这个?还有其他方法吗?

@Async
public CompletableFuture<String> doFoo() {

    CompletableFuture<String> completableFuture = new CompletableFuture<>();
    CompletableFuture.runAsync(() -> {
        try {
            String fooResult = longOp();
            completableFuture.complete(fooResult);
        } catch (Exception e) {
            completableFuture.completeExceptionally(e);
        }
    });
    return completableFuture;
}
Run Code Online (Sandbox Code Playgroud)

spring completable-future

15
推荐指数
1
解决办法
1万
查看次数

CompletableFuture runAsync vs supplyAsync,什么时候选择一个?

选择其中之一的理由是什么?阅读文档后我可以推断出的唯一区别是 runAsync 将 Runnable 作为输入参数,而 supplyAsync 将供应商作为输入参数。

这篇stackoverflow 帖子讨论了使用带有 supplyAsync 方法的供应商背后的动机,但它仍然没有回答何时选择一个而不是另一个。

java asynchronous java-8 completable-future

15
推荐指数
1
解决办法
9064
查看次数

等待多个CompletableFuture(直到最大超时)?

我最近刚刚开始使用 CompletableFuture,但遇到了一个问题,我有 N 个请求待办事项。

每个请求应发送到 2 个不同的端点,并应比较 JSON 格式的结果。由于我有大量的请求待办事项,并且我不知道每个请求需要多长时间,因此我想限制等待结果的时间,例如 3 秒左右。

所以我写了这个测试代码:

public class MainTest {

   private static final Logger logger = LoggerFactory.getLogger(MainTest.class);
   private Instant start;

   public static void main(String[] args) {

       MainTest main = new MainTest();
       main.start();
   }

   public void start(){
       String req1 = "http://localhost:8080/testing";
       String req2 = "http://127.0.0.1:8095/testing2";

       ExecutorService exec = Executors.newCachedThreadPool();

       start = Instant.now();
       CompletableFuture<String> comp1 = CompletableFuture.supplyAsync(() -> doReq(req1), exec);
       CompletableFuture<String> comp2 = CompletableFuture.supplyAsync(() -> doReq(req2), exec);


       List<CompletableFuture<String>> completables = List.of(comp1,comp2);

       logger.info("Waiting completables");

       CompletableFuture<List<String>> a = …
Run Code Online (Sandbox Code Playgroud)

java concurrency task completable-future unirest-java

15
推荐指数
1
解决办法
4万
查看次数

为什么即使我不调用 get() 或 join() 这个 CompletableFuture 也能工作?

我在学习时有一个问题CompletableFuture。将get()/join()方法阻塞调用。如果我不打电话给他们中的任何一个怎么办?

此代码调用get()

// Case 1 - Use get()
CompletableFuture.runAsync(() -> {
    try {
        Thread.sleep(1_000L);
    } catch (InterruptedException e) {
        e.printStackTrace();
    }
    System.out.println("Hello");
}).get();
System.out.println("World!");

Thread.sleep(5_000L); // Don't finish the main thread
Run Code Online (Sandbox Code Playgroud)

输出:

Hello
World!
Run Code Online (Sandbox Code Playgroud)

此代码既不调用get()也不调用join()

// Case 2 - Don't use get()
CompletableFuture.runAsync(() -> {
    try {
        Thread.sleep(1_000L);
    } catch (InterruptedException e) {
        e.printStackTrace();
    }
    System.out.println("Hello");
});
System.out.println("World!");

Thread.sleep(5_000L); // For don't finish main thread
Run Code Online (Sandbox Code Playgroud)

输出:

World!
Hello …
Run Code Online (Sandbox Code Playgroud)

java multithreading completable-future

15
推荐指数
3
解决办法
2183
查看次数

如何为CompletableFuture :: supplyAsync选择Executor

CompletableFuture::supplyAsync(() -> IO bound queries)

如何为CompletableFuture :: supplyAsync选择Executor以避免污染ForkJoinPool.commonPool().

有许多选项Executors(newCachedThreadPool,newWorkStealingPool,newFixedThreadPool等)

在这里阅读了关于新ForkJoinPool的内容

如何为我的用例选择合适的?

java executorservice java-8 threadpoolexecutor completable-future

14
推荐指数
1
解决办法
4726
查看次数

如何完成CompletableFuture <Void>?

我想要一个仅表示完成的CompletableFuture(例如,我没有返回值).

我可以将CompletableFuture实例化为:

CompletableFuture<Void> future = new CompletableFuture<> ();
Run Code Online (Sandbox Code Playgroud)

但是我应该为完整的方法提供什么?例如,我做不到

future.complete(new Void());
Run Code Online (Sandbox Code Playgroud)

java completable-future

14
推荐指数
1
解决办法
3734
查看次数

CompletableFuture.Delayer中的静态ScheduledThreadPoolExecutor

在java-9 中,引入了类中的新方法completeOnTimeoutCompletableFuture:

public CompletableFuture<T> completeOnTimeout(T value, long timeout,
                                              TimeUnit unit) {
    if (unit == null)
        throw new NullPointerException();
    if (result == null)
        whenComplete(new Canceller(Delayer.delay(
                                       new DelayedCompleter<T>(this, value),
                                       timeout, unit)));
    return this;
}
Run Code Online (Sandbox Code Playgroud)

我不明白为什么它在其实现中使用静态 ScheduledThreadPoolExecutor:

    static ScheduledFuture<?> delay(Runnable command, long delay,
                                    TimeUnit unit) {
        return delayer.schedule(command, delay, unit);
    }
Run Code Online (Sandbox Code Playgroud)

哪里

    static final ScheduledThreadPoolExecutor delayer;
    static {
        (delayer = new ScheduledThreadPoolExecutor(
            1, new DaemonThreadFactory())).
            setRemoveOnCancelPolicy(true);
    }
Run Code Online (Sandbox Code Playgroud)

对我来说这是一种非常奇怪的方法,因为它可能成为整个应用程序的瓶颈:唯一一个ScheduledThreadPoolExecutor只有一个线程保留在池中以执行所有可能的CompletableFuture任务?

我在这里错过了什么?

PS它看起来像:

1)这段代码的作者不愿意提取这种逻辑,而是倾向于重用ScheduledThreadPoolExecutor …

java multithreading threadpoolexecutor java-9 completable-future

14
推荐指数
1
解决办法
611
查看次数

CompletableFuture/ForkJoinPool设置类加载器

我解决了一个非常具体的问题,其解决方案似乎是基本的:

我的(Spring)应用程序的类加载器层次结构是这样的: SystemClassLoader -> PlatformClassLoader -> AppClassLoader

如果我使用Java CompleteableFuture来运行线程.该ContextClassLoader线程的是: SystemClassLoader -> PlatformClassLoader -> ThreadClassLoader

因此,AppClassLoader虽然我必须访问任何类,但我无法访问任何类,因为所有外部库类都驻留在那里.

源代码库非常大,所以我不希望/不能将所有与线程相关的部分重写为其他内容(例如,将自定义执行程序传递给每个调用).

所以我的问题是:我怎样才能创建线程,例如CompleteableFuture.supplyAsync()使用AppClassLoader父母作为父母?(而不是PlatformClassloader)

我发现ForkJoinPool用于创建线程.但在我看来,一切都是静态的最终的.所以我怀疑即使在系统属性中设置自定义ForkJoinWorkerThreadFactory也会有所帮助.或者是吗?

编辑以回答评论中的问题:

  • 你在哪里部署?这是在jetty/tomcat /任何JEE容器内运行吗?

    • 我正在使用默认的Spring Boot设置,因此使用了内部tomcat容器.
  • 你有什么确切的问题?

    • 确切的问题是:java.lang.IllegalArgumentException:从类加载器中看不到从方法引用的org.keycloak.admin.client.resource.RealmsResource
  • 您提交给supplyAsync()的作业是从AppClassLoader创建的,不是吗?

    • supplyAsync从被称为MainThread它使用AppClassLoader.但是,调试应用程序会显示所有此类线程都具有PlatformClassLoader父级.至于我的理解,这是因为ForkJoinPool.commonPool()是在应用程序启动期间构建的(因为它是静态的),所以使用默认的类加载器作为父类PlatformClassLoader.因此,此池中的所有线程都将PlatformClassLoader作为ContextClassLoader的父级(而不是AppClassLoader).

    • 当我在内部创建自己的执行程序MainThread并将此执行程序传递给supplyAsync所有工作时 - 我可以在调试期间看到确实现在AppClassLoader是我的父项ThreadClassLoader.这似乎证实了我在第一种情况下的假设,即公共池MainThread至少不是在它自己使用时创建的 …

java spring classloader completable-future

13
推荐指数
4
解决办法
1238
查看次数