Calling a lambda expression from a new thread before the main method is run causes the thread to lock up
David Holmes
david.holmes at oracle.com
Tue Jan 24 06:48:28 UTC 2017
Hi Luke,
On 24/01/2017 2:41 PM, Luke Hutchison wrote:
> 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.
That looks like a variation of the classic class initialization deadlock
problem. Your main thread is blocked in es.submit(callable).get(); while
still within the static initializer of the LambdaBug class. If the
executor thread also needs to ensure LambdaBug is initialized (which it
will in the lambda case) then it will wait for the main thread to
complete the initialization. Hence deadlock.
David
-----
> 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");
> }
> }
>
More information about the core-libs-dev
mailing list