问题
After tomcat upgrade from 8.5.6 to 8.5.28 parallel stream stopped supplying Threads with contextClassLoader:
Because of it Warmer::run
can't load classes in it.
warmers.parallelStream().forEach(Warmer::run);
Do you have any ideas what Tomcat was supplying for contextClassLoaders for new Threads?
ParallelStream uses ForkJoinPool in newest Tomcat.
回答1:
Common ForkJoin pool is problematic and could be responsible for memory leaks and for applications being able to load classes and resources from other contexts/applications (potential security leak if your tomcat is multi tenant). See this Tomcat Bugzilla Report.
In Tomcat 8.5.11 they had applied fix to the above issues by introducing SafeForkJoinWorkerThreadFactory.java
In order for your code to work, you can do the following, which will supply explicit ForkJoin and its worker thread factory to the Stream.parallel()
execution.
ForkJoinPool forkJoinPool = new ForkJoinPool(NO_OF_WORKERS);
forkJoinPool.execute(() -> warmers.parallelStream().forEach(Warmer::run));
回答2:
This saved my day! I had to do it like this to make it work:
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())
来源:https://stackoverflow.com/questions/49110537/parallel-stream-doesnt-set-thread-contextclassloader-after-tomcat-upgrade