Difference between thread's context class loader and normal classloader Difference between thread's context class loader and normal classloader multithreading multithreading

Difference between thread's context class loader and normal classloader


Each class will use its own classloader to load other classes. So if ClassA.class references ClassB.class then ClassB needs to be on the classpath of the classloader of ClassA, or its parents.

The thread context classloader is the current classloader for the current thread. An object can be created from a class in ClassLoaderC and then passed to a thread owned by ClassLoaderD. In this case the object needs to use Thread.currentThread().getContextClassLoader() directly if it wants to load resources that are not available on its own classloader.


This does not answer the original question, but as the question is highly ranked and linked for any ContextClassLoader query, I think it is important to answer the related question of when the context class loader should be used. Short answer: never use the context class loader! But set it to getClass().getClassLoader() when you have to call a method that is missing a ClassLoader parameter.

When code from one class asks to load another class, the correct class loader to use is the same class loader as the caller class (i.e., getClass().getClassLoader()). This is the way things work 99.9% of the time because this is what the JVM does itself the first time you construct an instance of a new class, invoke a static method, or access a static field.

When you want to create a class using reflection (such as when deserializing or loading a configurable named class), the library that does the reflection should always ask the application which class loader to use, by receiving the ClassLoader as a parameter from the application. The application (which knows all the classes that need constructing) should pass it getClass().getClassLoader().

Any other way to obtain a class loader is incorrect. If a library uses hacks such as Thread.getContextClassLoader(), sun.misc.VM.latestUserDefinedLoader(), or sun.reflect.Reflection.getCallerClass() it is a bug caused by a deficiency in the API. Basically, Thread.getContextClassLoader() exists only because whoever designed the ObjectInputStream API forgot to accept the ClassLoader as a parameter, and this mistake has haunted the Java community to this day.

That said, many many JDK classes use one of a few hacks to guess some class loader to use. Some use the ContextClassLoader (which fails when you run different apps on a shared thread pool, or when you leave the ContextClassLoader null), some walk the stack (which fails when the direct caller of the class is itself a library), some use the system class loader (which is fine, as long as it is documented to only use classes in the CLASSPATH) or bootstrap class loader, and some use an unpredictable combination of the above techniques (which only makes things more confusing). This has resulted in much weeping and gnashing of teeth.

When using such an API, first, try to find an overload of the method that accepts the class loader as a parameter. If there is no sensible method, then try setting the ContextClassLoader before the API call (and resetting it afterwards):

ClassLoader originalClassLoader = Thread.currentThread().getContextClassLoader();try {    Thread.currentThread().setContextClassLoader(getClass().getClassLoader());    // call some API that uses reflection without taking ClassLoader param} finally {    Thread.currentThread().setContextClassLoader(originalClassLoader);}


There is an article on infoworld.com that explains the difference=> Which ClassLoader should you use

(1)

Thread context classloaders provide aback door around the classloadingdelegation scheme.

Take JNDI for instance: its guts areimplemented by bootstrap classes inrt.jar (starting with J2SE 1.3), butthese core JNDI classes may load JNDIproviders implemented by independentvendors and potentially deployed inthe application's -classpath. Thisscenario calls for a parentclassloader (the primordial one inthis case) to load a class visible toone of its child classloaders (thesystem one, for example). Normal J2SEdelegation does not work, and theworkaround is to make the core JNDIclasses use thread context loaders,thus effectively "tunneling" throughthe classloader hierarchy in thedirection opposite to the properdelegation.

(2) from the same source:

This confusion will probably stay withJava for some time. Take any J2SE APIwith dynamic resource loading of anykind and try to guess which loadingstrategy it uses. Here is a sampling:

  • JNDI uses context classloaders
  • Class.getResource() and Class.forName() use the current classloader
  • JAXP uses context classloaders (as of J2SE 1.4)
  • java.util.ResourceBundle uses the caller's current classloader
  • URL protocol handlers specified via java.protocol.handler.pkgs system property are looked up in the bootstrap and system classloaders only
  • Java Serialization API uses the caller's current classloader by default