在 tomcat 从 8.5.6 升级到 8.5.28 并行流后停止为线程提供 contextClassLoader:
因为它Warmer::run
无法在其中加载类。
warmers.parallelStream().forEach(Warmer::run);
你知道 Tomcat 为新线程的 contextClassLoaders 提供了什么吗?
ParallelStream 在最新的 Tomcat 中使用 ForkJoinPool。
在 tomcat 从 8.5.6 升级到 8.5.28 并行流后停止为线程提供 contextClassLoader:
因为它Warmer::run
无法在其中加载类。
warmers.parallelStream().forEach(Warmer::run);
你知道 Tomcat 为新线程的 contextClassLoaders 提供了什么吗?
ParallelStream 在最新的 Tomcat 中使用 ForkJoinPool。
公共 ForkJoin 池存在问题,可能会导致内存泄漏以及应用程序能够从其他上下文/应用程序加载类和资源(如果您的 tomcat 是多租户,则可能存在安全漏洞)。请参阅此Tomcat Bugzilla 报告。
在Tomcat 8.5.11 中,他们通过引入对上述问题进行了修复SafeForkJoinWorkerThreadFactory.java
为了让您的代码工作,您可以执行以下操作,这将为执行提供显式ForkJoin及其工作线程工厂Stream.parallel()
。
ForkJoinPool forkJoinPool = new ForkJoinPool(NO_OF_WORKERS);
forkJoinPool.execute(() -> warmers.parallelStream().forEach(Warmer::run));
这拯救了我的一天!我必须这样做才能使其工作:
private static class CustomForkJoinWorkerThread extends ForkJoinWorkerThread {
CustomForkJoinWorkerThread(ForkJoinPool pool) {
super(pool);
setContextClassLoader(Thread.currentThread().getContextClassLoader());
}
}
private ForkJoinPool createForkJoinPool() {
return new ForkJoinPool(
ForkJoinPool.getCommonPoolParallelism(),
CustomForkJoinWorkerThread::new,
null,
false
);
}
createForkJoinPool().submit(() -> stuff.parallelStream().doStuff())