我学到的关于Java EE开发的第一件事就是我不应该在Java EE容器中生成我自己的线程.但是当我开始思考它时,我不知道原因.
你能清楚地解释为什么气馁吗?
我相信大多数企业应用程序都需要某种异步工作,如邮件守护进程,空闲会话,清理工作等.
因此,如果确实不应该生成线程,那么在需要时执行它的正确方法是什么?
我解决了一个非常具体的问题,其解决方案似乎是基本的:
我的(Spring)应用程序的类加载器层次结构是这样的: SystemClassLoader -> PlatformClassLoader -> AppClassLoader
如果我使用Java CompleteableFuture来运行线程.该ContextClassLoader线程的是: SystemClassLoader -> PlatformClassLoader -> ThreadClassLoader
因此,AppClassLoader虽然我必须访问任何类,但我无法访问任何类,因为所有外部库类都驻留在那里.
源代码库非常大,所以我不希望/不能将所有与线程相关的部分重写为其他内容(例如,将自定义执行程序传递给每个调用).
所以我的问题是:我怎样才能创建线程,例如CompleteableFuture.supplyAsync()使用AppClassLoader父母作为父母?(而不是PlatformClassloader)
我发现ForkJoinPool用于创建线程.但在我看来,一切都是静态的和最终的.所以我怀疑即使在系统属性中设置自定义ForkJoinWorkerThreadFactory也会有所帮助.或者是吗?
编辑以回答评论中的问题:
你在哪里部署?这是在jetty/tomcat /任何JEE容器内运行吗?
你有什么确切的问题?
您提交给supplyAsync()的作业是从AppClassLoader创建的,不是吗?
在supplyAsync从被称为MainThread它使用AppClassLoader.但是,调试应用程序会显示所有此类线程都具有PlatformClassLoader父级.至于我的理解,这是因为ForkJoinPool.commonPool()是在应用程序启动期间构建的(因为它是静态的),所以使用默认的类加载器作为父类PlatformClassLoader.因此,此池中的所有线程都将PlatformClassLoader作为ContextClassLoader的父级(而不是AppClassLoader).
当我在内部创建自己的执行程序MainThread并将此执行程序传递给supplyAsync所有工作时 - 我可以在调试期间看到确实现在AppClassLoader是我的父项ThreadClassLoader.这似乎证实了我在第一种情况下的假设,即公共池MainThread至少不是在它自己使用时创建的 …
我英语不好。
我使用异步方法。
选项1
public CompletableFuture<Integer> getDiscountPriceAsync(Integer price) {
return CompletableFuture.supplyAsync(() -> {
log.info("supplyAsync");
return (int)(price * 0.9);
}, threadPoolTaskExecutor);
}
Run Code Online (Sandbox Code Playgroud)
选项2
@Async
public CompletableFuture<Integer> getDiscountPriceAsync(Integer price) {
return CompletableFuture.supplyAsync(() -> {
log.info("supplyAsync");
return (int)(price * 0.9);
}, threadPoolTaskExecutor);
}
Run Code Online (Sandbox Code Playgroud)
我想知道使用 @Async 和不使用它有什么区别。
我认为第一个Option1提供了足够的异步方法。
但是,像Option2那样使用它是否正确呢?