并行流在tomcat升级后不设置Thread.contextClassLoader

one*_*eat 6 java contextclassloader forkjoinpool tomcat8 java-stream

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

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

warmers.parallelStream().forEach(Warmer::run);
Run Code Online (Sandbox Code Playgroud)

你有什么想法Tomcat为新线程提供contextClassLoaders的东西吗?

ParallelStream在最新的Tomcat中使用ForkJoinPool.

小智 8

这救了我的命!我必须这样做才能使其发挥作用:

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())
Run Code Online (Sandbox Code Playgroud)


dig*_*ise 6

常见的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));
Run Code Online (Sandbox Code Playgroud)