-
Bug
-
Resolution: Not an Issue
-
P3
-
12, 17, 18
A DESCRIPTION OF THE PROBLEM :
When we launch a Java class with "java FunBug.java", the Java class is loaded in the com.sun.tools.javac.launcher.Main$MemoryClassLoader. Furthermore, if we load the same class using reflectively using newInstanceFromSystemProperty() inside the ForkJoinPool, for example when we specify a threadFactory, then it will use the same class that we have loaded in the MemoryClassLoader and create an
instance to use as a thread factory. However, if we compile the class, and then run the Java class with "java FunBug.java", then the Java class is loaded in the MemoryClassLoader as before, but the class for the thread factory is loaded in the AppClassLoader. This means that we now have multiple class instances and
any static variables would be defined twice. It works fine if we run the Java class with "java FunBug" (without the .java extension) or if we do not compile it and run it with "java FunBug.java" (with the .java extension).
In Java 11, this condition caused the following error:
java -Djava.util.concurrent.ForkJoinPool.common.threadFactory=FunBug FunBug.java
Created FunBug class in jdk.internal.loader.ClassLoaders$AppClassLoader@77556fd
of jdk.internal.loader.ClassLoaders$PlatformClassLoader@3270d194
error: class found on application class path: FunBug
Since Java 12, it would instead load the class twice, giving mysterious bugs
REGRESSION : Last worked in version 11.0.14
STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
1. Compile the FunBug.java file with javac.
2. Run the code with java -Djava.util.concurrent.ForkJoinPool.common.threadFactory=FunBug FunBug.java
EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
Either:
Created FunBug class in com.sun.tools.javac.launcher.Main$MemoryClassLoader@35e2d654
of jdk.internal.loader.ClassLoaders$AppClassLoader@77556fd
of jdk.internal.loader.ClassLoaders$PlatformClassLoader@14cd1699
or
Created FunBug class in jdk.internal.loader.ClassLoaders$AppClassLoader@5c29bfd
of jdk.internal.loader.ClassLoaders$PlatformClassLoader@3a4afd8d
ACTUAL -
Created FunBug class in com.sun.tools.javac.launcher.Main$MemoryClassLoader@6b0c2d26
of jdk.internal.loader.ClassLoaders$AppClassLoader@75b84c92
of jdk.internal.loader.ClassLoaders$PlatformClassLoader@646be2c3
Created FunBug class in jdk.internal.loader.ClassLoaders$AppClassLoader@75b84c92
of jdk.internal.loader.ClassLoaders$PlatformClassLoader@646be2c3
Exception in thread "main" java.lang.NullPointerException
at FunBug.newThread(FunBug.java:21)
at java.base/java.util.concurrent.ForkJoinPool.createWorker(ForkJoinPool.java:1328)
at java.base/java.util.concurrent.ForkJoinPool.tryAddWorker(ForkJoinPool.java:1352)
at java.base/java.util.concurrent.ForkJoinPool.signalWork(ForkJoinPool.java:1476)
at java.base/java.util.concurrent.ForkJoinPool.externalPush(ForkJoinPool.java:1903)
at java.base/java.util.concurrent.ForkJoinTask.fork(ForkJoinTask.java:704)
at java.base/java.util.stream.ForEachOps$ForEachTask.compute(ForEachOps.java:306)
at java.base/java.util.concurrent.CountedCompleter.exec(CountedCompleter.java:746)
at java.base/java.util.concurrent.ForkJoinTask.doExec(ForkJoinTask.java:290)
at java.base/java.util.concurrent.ForkJoinTask.doInvoke(ForkJoinTask.java:408)
at java.base/java.util.concurrent.ForkJoinTask.invoke(ForkJoinTask.java:736)
at java.base/java.util.stream.ForEachOps$ForEachOp.evaluateParallel(ForEachOps.java:159)
at java.base/java.util.stream.ForEachOps$ForEachOp$OfInt.evaluateParallel(ForEachOps.java:188)
at java.base/java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:233)
at java.base/java.util.stream.IntPipeline.forEach(IntPipeline.java:439)
at java.base/java.util.stream.IntPipeline$Head.forEach(IntPipeline.java:596)
at FunBug.main(FunBug.java:28)
---------- BEGIN SOURCE ----------
import java.util.concurrent.ForkJoinPool;
import java.util.concurrent.ForkJoinWorkerThread;
import java.util.concurrent.locks.LockSupport;
import java.util.stream.IntStream;
public class FunBug implements ForkJoinPool.ForkJoinWorkerThreadFactory {
static {
System.out.println("Created FunBug class in " +
FunBug.class.getClassLoader());
ClassLoader parent = FunBug.class.getClassLoader().getParent();
while (parent != null) {
System.out.println("\tof " + parent);
parent = parent.getParent();
}
}
private static ForkJoinPool.ForkJoinWorkerThreadFactory defaultFactory;
@Override
public ForkJoinWorkerThread newThread(ForkJoinPool pool) {
return defaultFactory.newThread(pool);
}
public static void main(String... args) {
defaultFactory = ForkJoinPool.defaultForkJoinWorkerThreadFactory;
IntStream.range(0, Runtime.getRuntime().availableProcessors() * 8)
.parallel()
.forEach(i -> LockSupport.parkNanos(100_000_000));
}
}
---------- END SOURCE ----------
CUSTOMER SUBMITTED WORKAROUND :
Don't run the javac launcher with compiled classes. Use either "java FunBug" with compiled classes or "java FunBug.java" without compiled classes
FREQUENCY : always
When we launch a Java class with "java FunBug.java", the Java class is loaded in the com.sun.tools.javac.launcher.Main$MemoryClassLoader. Furthermore, if we load the same class using reflectively using newInstanceFromSystemProperty() inside the ForkJoinPool, for example when we specify a threadFactory, then it will use the same class that we have loaded in the MemoryClassLoader and create an
instance to use as a thread factory. However, if we compile the class, and then run the Java class with "java FunBug.java", then the Java class is loaded in the MemoryClassLoader as before, but the class for the thread factory is loaded in the AppClassLoader. This means that we now have multiple class instances and
any static variables would be defined twice. It works fine if we run the Java class with "java FunBug" (without the .java extension) or if we do not compile it and run it with "java FunBug.java" (with the .java extension).
In Java 11, this condition caused the following error:
java -Djava.util.concurrent.ForkJoinPool.common.threadFactory=FunBug FunBug.java
Created FunBug class in jdk.internal.loader.ClassLoaders$AppClassLoader@77556fd
of jdk.internal.loader.ClassLoaders$PlatformClassLoader@3270d194
error: class found on application class path: FunBug
Since Java 12, it would instead load the class twice, giving mysterious bugs
REGRESSION : Last worked in version 11.0.14
STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
1. Compile the FunBug.java file with javac.
2. Run the code with java -Djava.util.concurrent.ForkJoinPool.common.threadFactory=FunBug FunBug.java
EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
Either:
Created FunBug class in com.sun.tools.javac.launcher.Main$MemoryClassLoader@35e2d654
of jdk.internal.loader.ClassLoaders$AppClassLoader@77556fd
of jdk.internal.loader.ClassLoaders$PlatformClassLoader@14cd1699
or
Created FunBug class in jdk.internal.loader.ClassLoaders$AppClassLoader@5c29bfd
of jdk.internal.loader.ClassLoaders$PlatformClassLoader@3a4afd8d
ACTUAL -
Created FunBug class in com.sun.tools.javac.launcher.Main$MemoryClassLoader@6b0c2d26
of jdk.internal.loader.ClassLoaders$AppClassLoader@75b84c92
of jdk.internal.loader.ClassLoaders$PlatformClassLoader@646be2c3
Created FunBug class in jdk.internal.loader.ClassLoaders$AppClassLoader@75b84c92
of jdk.internal.loader.ClassLoaders$PlatformClassLoader@646be2c3
Exception in thread "main" java.lang.NullPointerException
at FunBug.newThread(FunBug.java:21)
at java.base/java.util.concurrent.ForkJoinPool.createWorker(ForkJoinPool.java:1328)
at java.base/java.util.concurrent.ForkJoinPool.tryAddWorker(ForkJoinPool.java:1352)
at java.base/java.util.concurrent.ForkJoinPool.signalWork(ForkJoinPool.java:1476)
at java.base/java.util.concurrent.ForkJoinPool.externalPush(ForkJoinPool.java:1903)
at java.base/java.util.concurrent.ForkJoinTask.fork(ForkJoinTask.java:704)
at java.base/java.util.stream.ForEachOps$ForEachTask.compute(ForEachOps.java:306)
at java.base/java.util.concurrent.CountedCompleter.exec(CountedCompleter.java:746)
at java.base/java.util.concurrent.ForkJoinTask.doExec(ForkJoinTask.java:290)
at java.base/java.util.concurrent.ForkJoinTask.doInvoke(ForkJoinTask.java:408)
at java.base/java.util.concurrent.ForkJoinTask.invoke(ForkJoinTask.java:736)
at java.base/java.util.stream.ForEachOps$ForEachOp.evaluateParallel(ForEachOps.java:159)
at java.base/java.util.stream.ForEachOps$ForEachOp$OfInt.evaluateParallel(ForEachOps.java:188)
at java.base/java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:233)
at java.base/java.util.stream.IntPipeline.forEach(IntPipeline.java:439)
at java.base/java.util.stream.IntPipeline$Head.forEach(IntPipeline.java:596)
at FunBug.main(FunBug.java:28)
---------- BEGIN SOURCE ----------
import java.util.concurrent.ForkJoinPool;
import java.util.concurrent.ForkJoinWorkerThread;
import java.util.concurrent.locks.LockSupport;
import java.util.stream.IntStream;
public class FunBug implements ForkJoinPool.ForkJoinWorkerThreadFactory {
static {
System.out.println("Created FunBug class in " +
FunBug.class.getClassLoader());
ClassLoader parent = FunBug.class.getClassLoader().getParent();
while (parent != null) {
System.out.println("\tof " + parent);
parent = parent.getParent();
}
}
private static ForkJoinPool.ForkJoinWorkerThreadFactory defaultFactory;
@Override
public ForkJoinWorkerThread newThread(ForkJoinPool pool) {
return defaultFactory.newThread(pool);
}
public static void main(String... args) {
defaultFactory = ForkJoinPool.defaultForkJoinWorkerThreadFactory;
IntStream.range(0, Runtime.getRuntime().availableProcessors() * 8)
.parallel()
.forEach(i -> LockSupport.parkNanos(100_000_000));
}
}
---------- END SOURCE ----------
CUSTOMER SUBMITTED WORKAROUND :
Don't run the javac launcher with compiled classes. Use either "java FunBug" with compiled classes or "java FunBug.java" without compiled classes
FREQUENCY : always