diff --git a/core/src/main/java/hudson/ClassicPluginStrategy.java b/core/src/main/java/hudson/ClassicPluginStrategy.java index 098e5661ba..0bfb106742 100644 --- a/core/src/main/java/hudson/ClassicPluginStrategy.java +++ b/core/src/main/java/hudson/ClassicPluginStrategy.java @@ -84,7 +84,7 @@ public class ClassicPluginStrategy implements PluginStrategy { */ private static final FilenameFilter JAR_FILTER = (dir, name) -> name.endsWith(".jar"); - private PluginManager pluginManager; + private final PluginManager pluginManager; /** * All the plugins eventually delegate this classloader to load core, servlet APIs, and SE runtime. @@ -244,7 +244,7 @@ public class ClassicPluginStrategy implements PluginStrategy { coreClassLoader.add(pkg); } - ClassLoader dependencyLoader = new DependencyClassLoader(coreClassLoader, archive, Util.join(dependencies,optionalDependencies)); + ClassLoader dependencyLoader = new DependencyClassLoader(coreClassLoader, archive, Util.join(dependencies,optionalDependencies), pluginManager); dependencyLoader = getBaseClassLoader(atts, dependencyLoader); return new PluginWrapper(pluginManager, archive, manifest, baseResourceURL, @@ -561,7 +561,7 @@ public class ClassicPluginStrategy implements PluginStrategy { /** * Used to load classes from dependency plugins. */ - final class DependencyClassLoader extends ClassLoader { + static final class DependencyClassLoader extends ClassLoader { /** * This classloader is created for this plugin. Useful during debugging. */ @@ -569,15 +569,22 @@ public class ClassicPluginStrategy implements PluginStrategy { private List dependencies; + private final PluginManager pluginManager; + /** - * Topologically sorted list of transient dependencies. + * Topologically sorted list of transient dependencies. Lazily initialized via double-checked locking. */ private volatile List transientDependencies; - DependencyClassLoader(ClassLoader parent, File archive, List dependencies) { + static { + registerAsParallelCapable(); + } + + DependencyClassLoader(ClassLoader parent, File archive, List dependencies, PluginManager pluginManager) { super(parent); this._for = archive; - this.dependencies = dependencies; + this.dependencies = Collections.unmodifiableList(new ArrayList<>(dependencies)); + this.pluginManager = pluginManager; } private void updateTransientDependencies() { @@ -586,7 +593,11 @@ public class ClassicPluginStrategy implements PluginStrategy { } private List getTransitiveDependencies() { - if (transientDependencies==null) { + List localTransientDependencies = transientDependencies; + if (localTransientDependencies == null) { + synchronized (this) { + localTransientDependencies = transientDependencies; + if (localTransientDependencies == null) { CyclicGraphDetector cgd = new CyclicGraphDetector() { @Override protected List getEdges(PluginWrapper pw) { @@ -610,9 +621,11 @@ public class ClassicPluginStrategy implements PluginStrategy { throw new AssertionError(e); // such error should have been reported earlier } - transientDependencies = cgd.getSorted(); + transientDependencies = localTransientDependencies = cgd.getSorted(); + } } - return transientDependencies; + } + return localTransientDependencies; } @Override