0

I have the below method in class A. All classes A,B,C and the main class from which 'A' is invoked are in the same jar.

public class A {    
    private static void init() {
        if (!init) {
            synchronized (B.class) {
                if (!init) {
                    map = C.creat();
                    init = true;
                }
            }
        }
    }
}

The code is throwing a Throwable, java.lang.NoClassDefFoundError at the synchronized block (Line no.4). What can be the reason as all the classes are in the same jar, there is no chance for not finding a class during run time.

I have gone through the solution in Existing Question but could not find a solution. Please help.

There are static initialization blocks and static variables in class B.

The issue can be fixed, if I use a static object/class A to Synchronize the piece of code instead of 'B'. I am curious to know why i faced the exception and how to fix it using class B only.

Community
  • 1
  • 1
  • 2
    Why are you using B.class to synchronize? I don't think that's a best practice. – duffymo Feb 01 '17 at 13:11
  • Could it be that the static blocks in B call the `A.init` method? – RealSkeptic Feb 01 '17 at 13:16
  • Can you show the package structure of the jar?You can you jd-gui to decompile – Optimus Feb 01 '17 at 13:25
  • @duffymo: Ya i know. I have changed it to a static object. Just curies to know why i faced error – Darshan Gopal R Feb 01 '17 at 13:58
  • @RealSkeptic: No it doesnot. – Darshan Gopal R Feb 01 '17 at 13:59
  • @Optimus: A and B are not in the same package . 'pack1.pack2.A' and pack1.pack3.B . But i do not think the package structure matters. – Darshan Gopal R Feb 01 '17 at 14:00
  • Yea package structure doesnt matter if you have compiled the code successfully i just wanted to know if the B.class file is present in the jar – Optimus Feb 01 '17 at 14:06
  • "Static block" is an incorrect term, a fact that is germane here. The correct term is "static initializer block" or "static initialization block". This directly bears on the question. I suspect that `B` was never initialized. – Lew Bloch Feb 01 '17 at 16:33
  • “There are static blocks and static variables in class B.” Great information. The appropriate answer is: there is a problem in either, A, B, or C. Don’t you think that posting complete code, including B and C and the declaration of A’s members that you are using in the method and, if you are in a good mood, the actual caller of that `init()` method, may help? – Holger Feb 01 '17 at 20:14
  • I guess synchronized(B.class) does not load class B if not loaded yet. You can check if class B's static initializer block is been invoked. This may vary on JVM versions too. – Xavier DSouza Feb 02 '17 at 05:53
  • @LewBloch: Thnks for the correction. editted the question – Darshan Gopal R Feb 02 '17 at 07:27
  • 1
    @Xavier DSouza If `B` has not yet loaded, the reference to `B.class` will load class `B`, as the JLS specifies. It will not initialize `B`, per what the JLS also specifies, hence the initializer blocks will not run until an intializing event occurs sometime thereafter. – Lew Bloch Feb 05 '17 at 01:28
  • @Holger: The complete classes are very big and cannot be placed here. I just took out the piece of code which is throwing exception. Also B is not referred any where else in A and C – Darshan Gopal R Feb 06 '17 at 04:47
  • @Optimus: I re checked. The class file is present in the jar. I also copied the jar again and changed the java version(6.15 to 6.45). Still faced the same issue. – Darshan Gopal R Feb 06 '17 at 04:50

3 Answers3

0

If you really compiled that code into a JAR; and that JAR contains B.class; then this can't happen.

The only options are: the JAR you are using got corrupted; or it doesn't contain what you assume it should contain.

Thus: verify your JAR. Something must be wrong about it. For example, use jar tf jarfile.jar to list the complete content; and check if B.class is really in.

GhostCat
  • 137,827
  • 25
  • 176
  • 248
0

Classes object or the metadata are loaded by the classloaders while bringing launching the Java App.

The above code may end up in the java.lang.NoClassDefFoundError due to the following.

1> The above static method init is invoked from within a static block in class A. It may happen that the class B is still not loaded before class A and the classloader tries to get lock on the class object (metadata) of class B and fails to find the definition of the class.

It works if you syncronise on A.class because the classloader has the class meta reference of it

In order to make work with class B.class you may have to lazily invoke the init method in class A and allow the classloader to load the meta information of the classes. Please avoid invoking the init() method in the class A from any static initializer block.

  • Not exactly correct. Reference to `B.class` will trigger loading of `B`. It's in the JLS. As is the fact that reference to `B.class` will not trigger class initialization. – Lew Bloch Feb 01 '17 at 16:30
0

Had anything referred to any method or variable in B prior to the use of B.class? If not, then B has not, repeat, not been initialized. Reference to the class literal does not trigger class initialization. "Static block" is an incorrect term. It's "static initializer block". Which didn't get run.

Use a final Object member of either A or B to synchronize, not the class literal.

Lew Bloch
  • 3,364
  • 1
  • 16
  • 10