I encountered the following case:
I have a Singleton:
public class BookManager {
private boplean initialized = false;
private static BookManager instance;
static {
instance = new BookManager();
}
public void init() {
//Performs some initialization code
initialized = true;
}
public List<Book> getAllBooks() {
if (!initialized) {
throw new Exception("Not initialized!");
}
//do some code to get the books list and return it
}
}
The singleton is initialized and the init method is called during the application initialization, and works well.
After some time (not sure why) -
The use case where the exception is thrown is at at the following code:
BookManager.getInstance().getAllBooks();
I am sure that "init" method was called when the application started,
so I suspect the BookManager class was unloaded.
And when the above call was made, the class was reloaded but no call to "init" method was made.
Can someone explain in what cases a class loader is being collected by GC ?
(why the class is begin unloaded?)
I could find no reference to unloading of classes in the JBoss class loading documentation. However if you check out chapter 12.7. Unloading of Classes and Interfaces of the JLS a class can only be unloaded once the class loader is no longer reachable. That means the application has to be undeployed first. This is something that's handled by the JVM so JBoss can't do much here.
Having that said, storing stuff in static variables is unsupported by Java EE.
What's the exception you get? NullPointerException? What you can do is attache a debugger and check the object id of BookManager.class in the #init and #getAllBooks method. If it's the same (which I assume) no unloading happened.
Related
I saw answers like these, tried to clarify via comments, and was unsatisfied by examples here.
Maybe it's time for this specific question...
Why enum singleton implementation is called lazy?
public enum EnumLazySingleton {
INSTANCE;
EnumLazySingleton() {
System.out.println("constructing: " + this);
}
public static void touchClass() {}
}
How it is different from eager implementation?
public class BasicEagerSingleton {
private static final BasicEagerSingleton instance = new BasicEagerSingleton();
public static BasicEagerSingleton getInstance() {
return instance;
}
private BasicEagerSingleton() {
System.out.println("constructing: " + this);
}
public static void touchClass() {}
}
Both will init instance without accessing INSTANCE/getInstance() - e.g. call touchClass().
public class TestSingleton {
public static void main(String... args) {
System.out.println("sleeping for 5 sec...");
System.out.println("touching " + BasicEagerSingleton.class.getSimpleName());
BasicEagerSingleton.touchClass();
System.out.println("touching " + EnumLazySingleton.class.getSimpleName());
EnumLazySingleton.touchClass();
}
}
Output:
sleeping for 5 sec...
touching BasicEagerSingleton
constructing: BasicEagerSingleton#7bfcd12c
touching EnumLazySingleton
constructing: INSTANCE
Now, we can say both are lazy. What is eager then?
It is clear how (e.g) "double-checked locking" way is actually lazy (and messy, and slow). But if enum is lazy, then any singleton is lazy due to inevitable class loading - in fact, everything is lazy. At which point will this distinction stop making any sense?
The first two linked answers (by Peter Lawrey and Joachim Sauer) both agree that enums are not lazily initialized. Answers in the third link are simply wrong about what lazy initialization means.
The recommendation to use enums as singletons originates from Josh Bloch's Effective Java. Notably, the chapter on enum singletons makes no mention of laziness. There is a later chapter dedicated to lazy initialization, that likewise makes no mention of enums. The chapter contains two highlights.
If you need to use lazy initialization for performance on a static field, use the lazy initialization holder class idiom.
If you need to use lazy initialization for performance on an instance field, use the double-check idiom.
Undoubtedly, enums would be another idiom on this list if they were in any way lazily initialized. In fact they are not, although confusion about the meaning of lazy initialization results in some incorrect answers, as the OP shows.
May I wager the following:
You are trying to identify 2 "processes" or ... "things" (let's make this easy to understand - because if I start saying "Code Blocks", it sounds more difficult)...
At some point the class-loader will run, and you would like to know what "things" will be executed when the class-loader loads a class.
At another point invoking a method on the class will cause another "thing" to run / execute, and you would like to know which, exactly, (which "processes") would start..
The following facts are relevant:
Static initializers are run when the class-loader loads the class. The class-loader will not load the class until the code that is
running encounters the need to load it (because a method or field has
been invoked) such as: touchClass()
If a singleton instance of EITHER a class, OR an enumerated type has a field that is being initialized in the static
part of the class it will be loaded as soon as you 'touch' the
class - because the Class-Loader runs all static initializations for a class or enum on loading.
Lazy loading, likely, (And this is my "interpretation" about what you are asking) would happen when a method invokation asks the class
to create a singleton instance - which could happen quite a bit of
time after the "loading" of the class or enum.
A class like the following:
public class LazySingleton
{
// At time of class-loading, this singleton is set to 'null'
private static singleton = null;
// This is a method that will not be invoked until it is called by
// some other code-block (some other "thing")... When "touchClass()"
// is called, the singleton instance is not created.
public static LazySingleton retrieveSingleton()
{
if (singleton == null) singleton = new LazySingleton();
return singleton;
}
// DOES NOTHING... The Singleton is *not* loaded, even though the
// Class Loader has already loaded this Java ".class" file
// into memory.
public static void touchClass() { }
private LazySingleton()
{ System.out.println("constructing: LazySingleton"); }
}
Here on the other hand:
public enum EagerEnum
{
// The class loader will run this constructor as soon as this 'enum'
// is loaded from a '.class' file (in JAR or on disk) into memory
MyEnumConstant();
private EagerEnum()
{ System.out.println("Eager Enum Constructed"); }
// This will cause the Class Loader to Load this enum from the
// Java ".class" File immediately, and the "MyEnumConstant" will
// also have to be loaded - meaning the constructor will be called.
public static void touchEnum() { }
}
So the following code would produce the output
LazySingleton.touchClass(); // Prints nothing
EagerEnum.touchClass(); // Prints "Eager Enum Constructed"
LazySingleton.getSingletonInstance(); // Prints "constructing: LazySingleton
This is the code I have:
public class StupidClass {
static {
System.out.println("Stupid class loaded!");
}
}
And the tests I have, which I run separately.
import org.junit.Test;
public class StupidTest {
#Test
public void foo() throws ClassNotFoundException {
final Class<?> stupidClass = Class.forName("StupidClass");
System.out.println(stupidClass.getSimpleName());
}
#Test
public void bar() throws ClassNotFoundException {
final Class<StupidClass> stupidClassClass = StupidClass.class;
System.out.println(stupidClassClass.getSimpleName());
}
}
When I run test foo I will see:
Stupid class loaded!
StupidClass
But when I run the test bar all I see is:
StupidClass
Quoting from this page..
Class objects are constructed automatically by the Java Virtual
Machine as classes are loaded and by calls to the defineClass method
in the class loader.
So my understanding is, in test bar, Stupid class is loaded, otherwise I would have seen a null I guess? So Class object is created because class itself is loaded..
And now quoting from this page
Static initialization blocks are run when the JVM (class loader - to
be specific) loads StaticClass (which occurs the first time it is
referenced in code).
So I am expecting to see the "Stupid class loaded!" text in test bar as well, but I am not.
Also quoting from Thinking in Java
Each of the classes Candy, Gum, and Cookie has a static clause that is
executed as the class is loaded for the first time.
which is not very accurate it seems..
What am I missing?
Static initialization blocks are run when the JVM (class loader - to be specific) loads StaticClass (which occurs the first time it is referenced in code).
The above quote is plain wrong, but it is just one instance of a very widespread misconception.
Class is not initialized when it's being loaded, but when a static class member is first referenced. This is precisely governed by the specification.
Class loading does not occur when the class is first referenced, but at an implementation-dependent point.
The last moment when the class must be loaded is when the class is referenced, which is not the same as referencing a class member.
Class.forName initializes the class by default, but you have the choice of calling an overload that takes a boolean initialize and supplying false. You'll get the class loaded without initializing.
Class Loading and initialization are 2 different things. A class can be loaded but not initialized until it is really necessary. Static initializers are run only when a class is being initialized <> NOT loaded, "initialized"
In the first case you are loading and initializing a class when you use class.forName(), that's why the static initializers are run and hence you see "Stupid class loaded!" as output . In the second case, you are just assigning a reference of the class, the class is loaded (use java -verbose:class to see what classes are loaded) but you aren't really initializing it (or to be more precise, not doing anything that forces the initializers to run). Thus you don't see the output as Stupid class loaded!. Try doing something like calling newInstance() on the class, it should force the initialization of the class and you should see Stupid class loaded!
My code :
public class CheckPalindrome {
public static void main(String[] args) {
Class<Test> t = Test.class;
}
}
// class being loaded
class Test {
static {
System.out.println("aaa");
}
}
Classes that are loaded
...
[Loaded Test from file:/Workspaces/SampleTest/Java8/bin/]
...
^ - This shows that the class is loaded but not initialized.
I have a simple singleton class in Java that looks like the following one:
public class Singleton{
private static Singleton instance;
private Singleton(){}
public static Singleton getInstance(){
if (instance == null){
instance = new Singleton();
}
return instance;
}
public void doSomething(){
...
}
}
My code also contains two classes, from now on called A and B, that both have the following structure:
public class Foo{
...
public void bar(){
...
Singleton.getInstance().doSomething();
...
}
...
}
During an execution the code in class A is executed first and therefore it silently instantiates the singleton instance. However, later on when B's code gets executed, the singleton instance is instantiated again, which is not what I want to achieve.
After a little investigation we found that class A and B use a different class loader, which means the singleton class is also loaded twice, resulting into two singleton instances.
I've looked for solutions to this issue on the web and found several (quite similar) pages, e.g. http://www.javaworld.com/article/2073352/core-java/simply-singleton.html?page=2 and http://snehaprashant.blogspot.nl/2009/01/singleton-pattern-in-java.html.
However, after trying out several options I still can't get it to work, mainly because I don't really know how to apply the solution(s) in the simple code listed above.
So my question is: can someone provide me with a (clue to a) practical solution for my code to the problem described above so that the singleton is only instantiated once regardless of the classloader being used?
I doubt the solution in the JavaWorld article works. getContextClassLoader(), and Singleton.class.getClassLoader() can return different classloaders each time. And if you got a consistent classloader, then the only way to use the class would be via reflection.
I guess they expect you to replace:
Singleton.getInstance().doSomething();
with:
try {
Object instance = getClass("package.Singleton").getMethod("getInstance").invoke(null);
instance.getClass().getMethod("doSomething").invoke(instance);
} catch (ReflectiveOperationException e) {
e.printStackTrace();
}
Instead, I would look at why there are multiple classloaders. Either keep all your code under the same classloader, or put the singleton into a common parent of both classloaders, and make the class unavailable to the child classloaders.
Looks like I am missing important concept on locking a class and it's related classloading event.As per my knowledge in java we can use any class only if classloader has already loaded the class ( byte code ) in memory. Based on this assumption I was thinking that "static block
of SharedQ class should execute when statement synchronized (SharedQ.class) { ... } executes in below code". But thats not the same.
Can anyone please explain what is happening here exactly.
public class VerifyClassLoadingOnClassLock {
public static void main(String[] args) {
show();
}
private static void show() {
synchronized (SharedQ.class) {
System.out.println(" Method Show() executing from Main() .... ");
}
}
}
public class SharedQ {
static {
System.out.println(" Classloader is loading SharedQ ");
}
public static void writeStream() {
// some multiThread code here
}
}
Output is : Method Show() executing from Main() ....
The class will have been loaded, but not necessarily initialized. Basically, there's a Class object available when you synchronize on it, but until something uses a member of the class, it doesn't have to be initialized.
From the JVM specification section 5.5:
Initialization of a class or interface consists of executing its class or interface initialization method (§2.9).
A class or interface may be initialized only as a result of:
The execution of any one of the Java Virtual Machine instructions new, getstatic, putstatic, or invokestatic that references the class or interface (§new, §getstatic, §putstatic, §invokestatic). All of these instructions reference a class directly or indirectly through either a field reference or a method reference.
Upon execution of a new instruction, the referenced class or interface is initialized if it has not been initialized already.
Upon execution of a getstatic, putstatic, or invokestatic instruction, the class or interface that declared the resolved field or method is initialized if it has not been initialized already.
The first invocation of a java.lang.invoke.MethodHandle instance which was the result of resolution of a method handle by the Java Virtual Machine (§5.4.3.5) and which has a kind of 2 (REF_getStatic), 4 (REF_putStatic), or 6 (REF_invokeStatic).
Invocation of certain reflective methods in the class library (§2.12), for example, in class Class or in package java.lang.reflect.
The initialization of one of its subclasses.
Its designation as the initial class at Java Virtual Machine start-up (§5.2).
Prior to initialization, a class or interface must be linked, that is, verified, prepared, and optionally resolved.
Section 5 of the specification talks a lot about all of this - in particular, it differentiates between loading, linking and verification.
I'm trying to define a custom ClassLoader.
public class ExampleLoader extends ClassLoader
{
public Class<?> findClass(String name) throws ClassNotFoundException
{
System.out.println("This never gets printed");
return super.findClass(name);
}
public Class<?> loadClass(String name, boolean b)
throws ClassNotFoundException
{
System.out.println("This never gets printed");
return super.loadClass(name, b);
}
}
And of course my code to test it:
public class Tester
{
public static void main(String[] args)
{
Thread t = new FooThread();
t.setContextClassLoader(new ExampleLoader());
t.start();
}
}
class FooThread extends Thread
{
public void run()
{
new RandomClass();
}
}
The problem is that my lines never get printed. Clearly I'm missing something.
This is related to bug 4868493. Here's a cite of relevance:
Unfortunately the documentation for getContextClassLoader and
setContextClassLoader might lead one to the conclusion that the
submitter's code should work as expected.
However, there is a basic rule in class loading - no class can ever
automatically load a class which is "downstream", i.e. which cannot
be directly loaded by that class' ClassLoader or one of its ancestor
ClassLoaders.
This is described in a number of places. For example, meditate on
the white paper available here:
http://www.javageeks.com/Papers/ClassForName/index.html
to gain enlightenment.
The key point seems to be that the context class loader is not used
automatically by the Java language. It's only a conventional place to
store the context class loader so that other classes can use it with the
3-argument form of Class.forName.
The spec for Thread.getContextClassLoader and Thread.setContextClassLoader
should be clarified, and the meaning of "context class loader" should
be clarified. Re-classifying as a doc bug.
The spec has not been clarified yet.
To get it to work what you initially want, replace new RandomClass() by
Class.forName(RandomClass.class.getName(),
true,
getContextClassLoader()).newInstance();
This prints, contradictorily, the following:
This never gets printed
Normally, all classloaders in a JVM are organized in a hierarchy such that every classloader (except for the primordial classloader that bootstraps the entire JVM) has a single parent. When asked to load a class, every compliant classloader is expected to delegate loading to its parent first and attempt to define the class only if the parent fails.
Same thing is happening in your case. "RandomClass" is to be loaded, ContextClassLoader delegates to its parent an so on. And one of parent class loader was able to load "RandomClass" (RandomClass was in classpath of parent). Because of this reason your SOP doesn't show up.
Reference following article little old but good:
http://www.javaworld.com/javaworld/javaqa/2003-06/01-qa-0606-load.html?page=1