The Java SE 7 release contains an important enhancement for multithreaded custom class loaders. In previous releases, certain types of custom class loaders were prone to deadlock. The Java SE 7 release modifies the locking mechanism to avoid deadlock.
The function of a
java.lang.ClassLoader is to
locate the bytecode for a particular class, then transform that
bytecode into a usable class in the runtime system. The runtime
system provides class loaders that can locate bootstrap classes,
extension classes, and user classes. The
environment variable is one way to indicate to the runtime system
where the bytecode is located.
Knowing about the
CLASSPATH environment variable is
all you may need to know about class loading. In some specific
situations, however, customizing the behavior of a class loader by
creating your own subclass may be necessary.
Custom class loaders will not run into deadlocks if they adhere
to an acyclic class loader delegation model. Acyclic delegation is
what the architects of
ClassLoader envisioned. In this
model, every class loader has a parent (delegate). When a class is
requested, the class loader first checks if the class was loaded
previously. If the class is not found, the class loader asks its
parent to locate the class. If the parent cannot find the class,
the class loader attempts to locate the class itself.
In earlier releases of the Java platform, multithreaded custom class loaders could deadlock when they did not have an acyclic delegation model. Here is one example:
Class Hierarchy: class A extends B class C extends D ClassLoader Delegation Hierarchy: Custom Classloader CL1: directly loads class A delegates to custom ClassLoader CL2 for class B Custom Classloader CL2: directly loads class C delegates to custom ClassLoader CL1 for class D Thread 1: Use CL1 to load class A (locks CL1) defineClass A triggers loadClass B (try to lock CL2) Thread 2: Use CL2 to load class C (locks CL2) defineClass C triggers loadClass D (try to lock CL1)
Synchronization in the
ClassLoader class was
previously heavy-handed, or in technical terms, not sufficiently
granular. A request to load a class synchronized on the entire
ClassLoader object, which made it prone to
The Java SE 7 release includes the concept of a parallel capable class loader. Loading a class by a parallel capable class loader now synchronizes on the pair consisting of the class loader and the class name.
In the previous scenario, using the Java SE 7 release, the threads are no longer deadlocked, and all classes are loaded successfully:
Thread 1: Use CL1 to load class A (locks CL1+A) defineClass A triggers loadClass B (locks CL2+B) Thread 2: Use CL2 to load class C (locks CL2+C) defineClass C triggers loadClass D (locks CL1+D)
Custom class loaders that do not have a history of deadlocks do not require any changes. In particular, you do not need to change custom class loaders that follow the recommended acyclic hierarchical delegation model, that is, delegating first to their parent class. For backward compatibility, the Java SE 7 release continues to lock a class loader object unless it registers as parallel capable.
To create new custom class loaders, the process is similar in
the Java SE 7 release as in previous releases. Create a subclass of
ClassLoader, then override the
findClass() method and possibly
your life more difficult, but it is the only way to use a different
If you have a custom class loader with a risk of deadlocking, with the Java SE 7 release, you can avoid deadlocks by following these rules:
java.lang.ClassLoaderuses a locking scheme based on the requested class name.
java.lang.ClassLoader's static method
registerAsParallelCapable(). This registration indicates that all instances of your custom class loader are multithread safe.
registerAsParallelCapable()method in their class initializers. Ensure that they are multithread safe for concurrent class loading.
If your custom class loader overrides only
findClass(String), you do not need further changes.
This is the recommended mechanism to create a custom class
If your custom class loader overrides either the
loadClass(String, boolean) method or the
loadClass(String) method, you must also ensure that the
defineClass() method is called only once for
each class loader and class name pair.
If your product ships and appears to have problems due to
incomplete handling of critical sections, you can use a new VM flag
-XX:+AlwaysLockClassLoader. This flag reverts to
locking the class loader lock before invoking your custom class
method, even for class loaders that register as parallel