7

在 tomcat 从 8.5.6 升级到 8.5.28 并行流后停止为线程提供 contextClassLoader:

因为它Warmer::run无法在其中加载类。

warmers.parallelStream().forEach(Warmer::run);

你知道 Tomcat 为新线程的 contextClassLoaders 提供了什么吗?

ParallelStream 在最新的 Tomcat 中使用 ForkJoinPool。

4

2 回答 2

7

公共 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));
于 2018-03-05T15:02:12.167 回答
4

这拯救了我的一天!我必须这样做才能使其工作:

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())
于 2018-06-28T10:18:17.863 回答