【问题标题】:Classes not loading properly within CompletableFuture类在 CompletableFuture 中未正确加载
【发布时间】:2018-10-22 10:33:29
【问题描述】:

下面是我使用 CompletableFuture 编写的代码 -

CompletableFuture<String> completableFuture = CompletableFuture.supplyAsync(() -> {
    printResult();
    return "complete future!";
});

在上面的代码中,在 printResult 函数中,我使用了一些与 xerces 相关的类来进行一些身份验证,这给了我 SAX2 driver class not found 错误!

但是,当我使用 Callable 编写相同的代码时,它运行良好 -

Callable<String> callableFuture = () -> { 
    printResult(); 
    return "callable!";  
};

此外,printResult() 在 CompletableFuture 之外也可以正常工作。只是想知道这里是否有人知道这里出了什么问题。感谢您的帮助!

编辑:我在日志中挖掘了一下,这是实际的错误消息 - {ForkJoinPool.commonPool-worker-2} | [---] |错误:未找到 SAX2 驱动程序类 org.apache.xerces.parsers.SAXParser

【问题讨论】:

  • 您如何在代码中使用callableFuture
  • 使用执行器服务 - executor.submit(callableFuture);
  • 如果您为您的CompletableFuture 使用相同的执行器服务,例如CompletableFuture.supplyAsync(() -&gt; { printResult(); return "complete future!"; }, executor),那又会怎样?
  • @Holger - 我刚刚实施了你的问题/解决方案,它奏效了!非常感谢。以前我直接运行 CompletableFuture 而不使用 executor-completableFuture.get()。它在将执行程序传递给 CompletableFuture 后工作。仍然困惑为什么?
  • 显然,您在 printResult() 中使用的 xerces 相关类取决于调用线程。 CompletableFuture…Async… 方法默认使用 ForkJoinPool.commonPool(),它使用除 executor 之外的其他线程,这些差异似乎与此处相关。在我看来,代码不应该对实际线程有这样的依赖,然而,这样的依赖,比如使用Thread.getContextClassLoader(),实际上非常普遍……

标签: java multithreading java-8 completable-future


【解决方案1】:

Callable 只是一个接口(@98​​7654322@ 也是如此),它不假设任何关于调用它的上下文。

CompletableFuture::supplyAsync(Supplier&lt;U&gt; supplier) 与其文档不同:

返回一个新的 CompletableFuture,它由在 ForkJoinPool.commonPool() 中运行的任务异步完成,其值通过调用给定的供应商获得。

因此,在您的情况下,您得到的错误(“SAX2 driver not found error!”)可能是由于当从CompletableFuture 执行printResult() 时,SAX2 驱动程序尚未执行尚未加载。

【讨论】:

  • 感谢您的回答。我在 CompletableFuture 中的 printResult() 之前手动尝试加载类,但仍然出现同样的错误。
【解决方案2】:

我猜你可能在 JEE/tomcat/spring-boot 应用程序中遇到问题。

在这样的应用程序中,有多个 ClassLoader 和 Threads 运行以启动和加载框架和其他子系统的 JAR。

CompletableFuture.supplyAsync

Returns a new CompletableFuture that is asynchronously completed by a task running in the ForkJoinPool.commonPool() with the value obtained by calling the given Supplier.

由于供应商在 JVM 管理的线程池中运行,因此该线程的 ClassLoader 不太可能由框架管理。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2015-07-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-05-13
    相关资源
    最近更新 更多