If you run the code below, the active JVM thread (in the ExecutorService)
locks up when the lambda expression is called. The Eclipse debugger is not
able to stop the locked-up thread, or get a stacktrace beyond the call into
the lambda.
The problem seems to be that some part of the Java 8 lambda system is not
properly initialized until just before the main method is called. This
problem is only exhibited if you call a lambda expression from a new
thread, spawned by a static initializer block, before the main method is
executed.
Reproducibility: 100%. (If you change the value of either or both of the
static boolean fields, the code completes as expected.)
This problem exists in both Oracle jdk1.8.0_121 and Fedora OpenJDK
1.8.0.111 (64 bit).
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class LambdaBug {
// Code will hang after "Entering startUp()" if both of these are true
private static final boolean RUN_AS_STATIC_INITIALIZER = true;
private static final boolean RUN_USING_LAMBDA = true;
static {
if (RUN_AS_STATIC_INITIALIZER) {
startUp();
}
}
private static void startUp() {
System.out.println("Entering startUp()");
ExecutorService es = Executors.newSingleThreadExecutor();
try {
Callable<Void> callable;
if (RUN_USING_LAMBDA) {
callable = () -> {
System.out.println("Lambda executed");
return null;
};
} else {
callable = new Callable<Void>() {
@Override
public Void call() throws Exception {
System.out.println("Inner class method executed");
return null;
}
};
}
es.submit(callable).get();
} catch (InterruptedException | ExecutionException e) {
throw new RuntimeException(e);
} finally {
es.shutdown();
}
System.out.println("Exiting startUp()");
}
public static void main(String[] args) {
if (!RUN_AS_STATIC_INITIALIZER) {
startUp();
}
System.out.println("Exiting main");
}
}