因此,这是一个非常肮脏的解决方案,我不为此感到骄傲,如果您继续使用它, 可能会为您 带来麻烦:
问题是该应用程序的类加载器未用于
ForkJoinPool.commonPool()。由于commonPool的设置是静态的,因此在应用程序启动期间,不容易(至少据我所知)以后进行更改。因此,我们需要依赖
Java反射API 。
在应用程序成功启动后创建一个钩子
- 就我而言(Spring Boot环境),这将是ApplicationReadyEvent
- 要收听此事件,您需要以下组件
@Component
class ForkJoinCommonPoolFix : ApplicationListener {
override fun onApplicationEvent(event: ApplicationReadyEvent?) {
}
}
在挂钩中,您需要将
ForkJoinWorkerThreadFactory
commonPool 设置为自定义实现(因此此自定义实现将使用应用程序类加载器)- 在科特林
val javaClass = ForkJoinPool.commonPool()::class.java
val field = javaClass.getDeclaredField(“factory”)
field.isAccessible = true
val modifiers = field::class.java.getDeclaredField(“modifiers”)
modifiers.isAccessible = true
modifiers.setInt(field, field.modifiers and Modifier.FINAL.inv())
field.set(ForkJoinPool.commonPool(), CustomForkJoinWorkerThreadFactory())
field.isAccessible = false
- 在科特林
简单实施
CustomForkJoinWorkerThreadFactory
- 在科特林
//Custom class
class CustomForkJoinWorkerThreadFactory : ForkJoinPool.ForkJoinWorkerThreadFactory {
override fun newThread(pool: ForkJoinPool?): ForkJoinWorkerThread {
return CustomForkJoinWorkerThread(pool)
}
}
// helper class (probably only needed in kotlin)
class CustomForkJoinWorkerThread(pool: ForkJoinPool?) : ForkJoinWorkerThread(pool)
- 在科特林
如果您需要 有关反射的更多信息
以及为什么更改最终字段不好,请参阅此处和此处。简短摘要:由于优化,更新的最终字段可能对其他对象不可见,并且可能发生其他未知的副作用。
如前所述:这是一个非常肮脏的解决方案。
如果使用此解决方案,可能会发生有害的副作用。使用这样的反射不是一个好主意。如果您可以使用没有反思的解决方案(并在此处发布答案!)。
编辑:单个呼叫的替代
就像问题本身所指出的那样:如果您仅在少数几个地方遇到此问题(即自行解决此问题本身就没有问题),则可以使用自己的Executor。从此处复制的一个简单示例:
ExecutorService pool = Executors.newFixedThreadPool(10);final CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> { }, pool);


