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 09:24:25 UTC 2017
On 24/01/2017 5:21 PM, Luke Hutchison wrote:
> On Mon, Jan 23, 2017 at 10:48 PM, David Holmes <david.holmes at oracle.com
> <mailto:david.holmes at oracle.com>> wrote:
>
> 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.
>
>
> Thanks for the explanation -- although I don't understand why a lambda
> expression requires its defining class to be initialized, whereas an
> anonymous inner class does not. The lambda body does not refer to the
> LambdaBug class. This must be due to an implicit reference to the
> defining class being added by the compiler for purposes of capturing the
> lexical scope (with this issue not getting triggered in the case of
> anonymous inner classes due to scoping differences)? However, why is the
> containing class reference even used in this case, when variables in the
> containing scope are not referenced?
I'd have to look at the exact code being generated for the lambda, but
the enclosing class plays as special role with lambdas and so needs to
be initialized before it can be used. There may be some scope for
adjusting this.
> If this is due to lexical scoping, shouldn't the compiler be able to add
> some runtime code to detect cases of this kind of deadlock, and throw a
> RuntimeException, or potentially even detect some of these cases statically?
Deadlock detection is out of scope for javac.
> Why is it possible to directly call lambdas inside a static initializer
> block without causing a deadlock (in other words, why is there no
> deadlock as long as the lambdas are not executed on a different thread
> while the main thread blocks)? The calling class is still not completely
> initialized when calling lambdas directly in a static initializer block
> on the main thread.
You need two threads for a deadlock. If the lambda code is called on the
main thread and accesses the LambdaBug class it will see it as a
recursive initialization attempt and simply return.
David
More information about the core-libs-dev
mailing list