----- Mail original -----
> De: "Luke Hutchison" <luke.hu...@gmail.com>
> À: "David Holmes" <david.hol...@oracle.com>
> Cc: core-libs-dev@openjdk.java.net
> Envoyé: Mardi 24 Janvier 2017 08:21:39
> Objet: Re: Calling a lambda expression from a new thread before the main      
> method is run causes the thread to lock up

> On Mon, Jan 23, 2017 at 10:48 PM, David Holmes <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?

The body of a lambda is desugared by the compiler into a static method, so when 
you submit the callable, a worker thread of the executor will try to execute 
the code of the static method but because the static initializer is not 
finished, the worker thread has to wait, then you call get() inside the static 
block that waits that the worker thread to finish its work => deadlock.

In case of an inner class, your code is in the inner class so the worker thread 
don't wait the static block to be finished, so no deadlock

As a rule of thumb, never starts a thread in a static block, you will get this 
classical deadlock AND your code is hard to test because static blocks tend to  
be executed in a random order (i.e. class loading is lazy so execution of 
static blocks are lazy too). 

> 
> 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?
> 
> 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.

cheers,
Rémi

Reply via email to