--- old/src/share/classes/java/lang/ClassLoader.java 2012-12-05 06:55:48.132052889 -0500 +++ new/src/share/classes/java/lang/ClassLoader.java 2012-12-05 06:55:47.228003356 -0500 @@ -108,6 +108,19 @@ * duration of the class loading process (see {@link #loadClass * loadClass} methods). * + *
Regular parallel capable class loaders may still need to use some form + * of synchronization to control concurrent load attempts of a given class. + * The {@link #getClassLoadingLock getClassLoadingLock} method is used to + * provide that object for use by {@link #loadClass loadClass}. A class loader + * can support fully concurrent loading of any class, in which case no + * synchronization need be used. Such parallel capable class loaders are + * required to register themselves at their class initialization time by + * invoking the + * {@link #registerAsFullyConcurrent registerAsFullyConcurrent} method. + * Note that the ClassLoader class is registered as fully + * concurrent by default. However, its subclasses still need to register + * themselves if they capable of fully concurrent class loading. + * *
Normally, the Java virtual machine loads classes from the local file
* system in a platform-dependent manner. For example, on UNIX systems, the
* virtual machine loads classes from the directory defined by the
@@ -193,27 +206,33 @@
private ParallelLoaders() {}
// the set of parallel capable loader types
- private static final Set Subclasses of ClassLoader are encouraged to override {@link
* #findClass(String)}, rather than this method. Unless overridden, this method synchronizes on the result of
- * {@link #getClassLoadingLock getClassLoadingLock} method
- * during the entire class loading process.
+ * Unless overridden, if this loader is not fully concurrent then
+ * this method synchronizes on the result
+ * of the {@link #getClassLoadingLock getClassLoadingLock} method
+ * during the entire class loading process. For a fully concurrent loader
+ * no synchronization occurs.
*
* @param name
* The binary name of the class
@@ -400,39 +437,56 @@
protected Class> loadClass(String name, boolean resolve)
throws ClassNotFoundException
{
- synchronized (getClassLoadingLock(name)) {
- // First, check if the class has already been loaded
- Class> c = findLoadedClass(name);
- if (c == null) {
- long t0 = System.nanoTime();
- try {
- if (parent != null) {
- c = parent.loadClass(name, false);
- } else {
- c = findBootstrapClassOrNull(name);
- }
- } catch (ClassNotFoundException e) {
- // ClassNotFoundException thrown if class not found
- // from the non-null parent class loader
- }
-
- if (c == null) {
- // If still not found, then invoke findClass in order
- // to find the class.
- long t1 = System.nanoTime();
- c = findClass(name);
-
- // this is the defining class loader; record the stats
- sun.misc.PerfCounter.getParentDelegationTime().addTime(t1 - t0);
- sun.misc.PerfCounter.getFindClassTime().addElapsedTimeFrom(t1);
- sun.misc.PerfCounter.getFindClasses().increment();
+ Class> c = null;
+ if (!isFullyConcurrent) {
+ synchronized (getClassLoadingLock(name)) {
+ c = do_loadClass(name);
+ if (resolve) {
+ resolveClass(c);
}
}
+ }
+ else {
+ c = do_loadClass(name);
if (resolve) {
resolveClass(c);
}
- return c;
}
+ return c;
+ }
+
+
+ private Class> do_loadClass(String name)
+ throws ClassNotFoundException
+ {
+ // First, check if the class has already been loaded
+ Class> c = findLoadedClass(name);
+ if (c == null) {
+ long t0 = System.nanoTime();
+ try {
+ if (parent != null) {
+ c = parent.loadClass(name, false);
+ } else {
+ c = findBootstrapClassOrNull(name);
+ }
+ } catch (ClassNotFoundException e) {
+ // ClassNotFoundException thrown if class not found
+ // from the non-null parent class loader
+ }
+
+ if (c == null) {
+ // If still not found, then invoke findClass in order
+ // to find the class.
+ long t1 = System.nanoTime();
+ c = findClass(name);
+
+ // this is the defining class loader; record the stats
+ sun.misc.PerfCounter.getParentDelegationTime().addTime(t1 - t0);
+ sun.misc.PerfCounter.getFindClassTime().addElapsedTimeFrom(t1);
+ sun.misc.PerfCounter.getFindClasses().increment();
+ }
+ }
+ return c;
}
/**
@@ -464,6 +518,9 @@
lock = newLock;
}
}
+ else if (isFullyConcurrent) {
+ lock = null; // TBD: is this the best thing to return?
+ }
return lock;
}
@@ -473,7 +530,7 @@
{
// For backward compatibility, explicitly lock on 'this' when
// the current class loader is not parallel capable.
- if (parallelLockMap == null) {
+ if (!isParallelCapable()) {
synchronized (this) {
return loadClass(name);
}
@@ -928,7 +985,7 @@
certs = cs.getCertificates();
}
Certificate[] pcerts = null;
- if (parallelLockMap == null) {
+ if (!isParallelCapable()) {
synchronized (this) {
pcerts = package2certs.get(pname);
if (pcerts == null) {
@@ -1230,6 +1287,9 @@
* registered as parallel capable
+ * Class loaders that are fully concurrent parallel capable should + * use {@link #registerAsFullyConcurrent} to register.
* * @return true if the caller is successfully registered as * parallel capable and false if otherwise. @@ -1237,7 +1297,27 @@ * @since 1.7 */ protected static boolean registerAsParallelCapable() { - return ParallelLoaders.register(getCaller(1)); + return ParallelLoaders.register(getCaller(1), false); + } + + /** + * Registers the caller as a fully concurrent parallel capable + * class loader. + * The registration succeeds if and only if all of the following + * conditions are met: