On 24/01/2017 5:21 PM, Luke Hutchison wrote:
On Mon, Jan 23, 2017 at 10:48 PM, David Holmes <david.hol...@oracle.com
<mailto:david.hol...@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

Reply via email to