[concurrency-interest] Single-threaded ForkJoinPool

cowwoc cowwoc at bbs.darktech.org
Mon Feb 8 03:10:37 EST 2016


I stepped through the ForkJoinPool code and saw the following execution 
path:

 1. ForkJoinPool.execute() -> ForkJoinPool.externalPush() ->
    ForkJoinPool.signalWork() -> ForkJoinPool.tryAddWorker() ->
    ForkJoinPool.createWorker() -> ForkJoinWorkerThreadFactory.newThread()
 2. When the factory returns null, createWorker() tries to clean up any
    exceptions (there are none) and all other methods return normally
    (as if a new thread had been created).
 3. This means that ForkJoinTask.get() will block indefinitely.

Doug is right that ForkJoinPool doesn't fail if a factory returns null, 
but it doesn't seem to recheck if a new worker is required unless 
someone adds additional tasks.

My guess is that tryAddWorker() should check if a worker was actually 
added as opposed to always breaking out of the loop.

Gili

On 2016-02-08 3:39 AM, cowwoc wrote:
> So, it turns out this solution isn't actually safe.
>
> 1. I used the following thread factory:
>
>                 ForkJoinWorkerThreadFactory factory = new 
> ForkJoinWorkerThreadFactory()
>                 {
>                     private WeakReference<Thread> currentWorker = new 
> WeakReference<>(null);
>
>                     @Override
>                     public synchronized ForkJoinWorkerThread 
> newThread(ForkJoinPool pool)
>                     {
>                         // If the pool already has a live thread, 
> return null.
>                         Thread thread = currentWorker.get();
>                         if (thread != null && thread.isAlive())
>                         {
>                             System.out.println("Thread: " + 
> thread.getName() + " is already alive, returning null.");
>                             return null;
>                         }
>                         ForkJoinWorkerThread result = new 
> MyForkJoinWorkerThread(pool);
>                         currentWorker = new WeakReference<>(result);
>                         // According to Doug Lea this will reduce the 
> probability of short livelocks
>                         Thread.yield();
>                         return result;
>                     }
>                 };
>
> 2. I started a debugging session.
> 3. I suspended all threads long enough for the worker thread to get 
> flagged as idle (approximately 10 seconds).
> 4. I allowed all threads to continue execution.
> 5. Upon resuming, the worker thread shut down and at the same time the 
> factory printed "Thread: X is already alive, returning null."
> 6. If I run the above scenario without suspending all threads (only 
> suspending the "main" thread) then the worker thread shuts down, I 
> resume execution, and a new worker thread spins up.
>
> In other words, the proposed solution is vulnerable to a race condition.
>
> Gili
>
> On 2016-02-06 9:35 PM, cowwoc wrote:
>> Thanks Doug, I'll give this a try.
>>
>> Thanks,
>> Gili
>>
>> On 2016-02-06 3:02 PM, Doug Lea [via JSR166 Concurrency] wrote:
>>> On 02/06/2016 05:21 AM, Viktor Klang wrote:
>>> > What happens if you supply it with a thread factory which only 
>>> allows a single
>>> > thread to be alive at a time, and returns null if it already has 
>>> returned a
>>> > still living thread?
>>> >
>>>
>>> Yes, this will work if you are positive that only one thread
>>> is required for liveness. FJ sometimes conservatively creates
>>> threads when it cannot itself guarantee liveness (for example,
>>> when GC or other system load causes stalls). But it will
>>> respond to null factory returns by rechecking, not failing.
>>> unless a thread really is needed to maintain liveness, in which
>>> case the program may livelock. To reduce transient near-livelock,
>>> you might want to place a Thread.yield() call before the
>>> "return null" in the factory.
>>>
>>> -Doug
>>>
>>>
>>> > --
>>> > Cheers,
>>> > √
>>> >
>>> > On Feb 6, 2016 05:19, "cowwoc" <[hidden email] 
>>> </user/SendEmail.jtp?type=node&node=13243&i=0>
>>> > <mailto:[hidden email] 
>>> </user/SendEmail.jtp?type=node&node=13243&i=1>>> wrote:
>>> >
>>> >     Hi,
>>> >
>>> >     Is this the correct mailing list for discussing ForkJoinPool 
>>> in JDK9? If
>>> >     not, please point me to the right place.
>>> >
>>> >     I have a feature request for ForkJoinPool which doesn't seem 
>>> to be possible
>>> >     to implement without a JDK change: 
>>> http://stackoverflow.com/q/34012134/14731
>>> >
>>> >     Specifically, I need to be able to an application that uses 
>>> Random and
>>> >     ForkJoinPool in a deterministic manner when 
>>> debugging/profiling but run
>>> >     full-speed in normal execution mode. I have all the moving 
>>> parts nailing
>>> >     down except for ForkJoinPool.
>>> >
>>> >     If I create ForkJoinPool with a parallelism of 1, sometimes I 
>>> see two worker
>>> >     threads getting used. I am guessing that this is caused by
>>> >     ForkJoinTask.get() invoking 
>>> ForkJoinPool.common.externalHelpComplete(), but
>>> >     maybe something else is going on.
>>> >
>>> >     Is there a way for me to guarantee that ForkJoinThread will 
>>> use exactly 1
>>> >     worker thread, no less, no more? Would you like me to file a 
>>> formal feature
>>> >     request?
>>> >
>>> >     Thank you,
>>> >     Gili
>>> >
>>> >
>>> >
>>> >     --
>>> >     View this message in context:
>>> > 
>>> http://jsr166-concurrency.10961.n7.nabble.com/Single-threaded-ForkJoinPool-tp13232.html
>>> >     Sent from the JSR166 Concurrency mailing list archive at 
>>> Nabble.com.
>>> >     _______________________________________________
>>> >     Concurrency-interest mailing list
>>> > [hidden email] </user/SendEmail.jtp?type=node&node=13243&i=2> 
>>> <mailto:[hidden email] </user/SendEmail.jtp?type=node&node=13243&i=3>>
>>> > http://cs.oswego.edu/mailman/listinfo/concurrency-interest
>>> >
>>> >
>>> >
>>> > _______________________________________________
>>> > Concurrency-interest mailing list
>>> > [hidden email] </user/SendEmail.jtp?type=node&node=13243&i=4>
>>> > http://cs.oswego.edu/mailman/listinfo/concurrency-interest
>>> >
>>>
>>>
>>>
>>> _______________________________________________
>>> Concurrency-interest mailing list
>>> [hidden email] </user/SendEmail.jtp?type=node&node=13243&i=5>
>>> http://cs.oswego.edu/mailman/listinfo/concurrency-interest
>>>
>>>
>>> ------------------------------------------------------------------------
>>> If you reply to this email, your message will be added to the 
>>> discussion below:
>>> http://jsr166-concurrency.10961.n7.nabble.com/Single-threaded-ForkJoinPool-tp13232p13243.html 
>>>
>>> To unsubscribe from Single-threaded ForkJoinPool, click here 
>>> <http://jsr166-concurrency.10961.n7.nabble.com/template/NamlServlet.jtp?macro=unsubscribe_by_code&node=13232&code=Y293d29jQGJicy5kYXJrdGVjaC5vcmd8MTMyMzJ8MTU3NDMyMTI0Nw==>.
>>> NAML 
>>> <http://jsr166-concurrency.10961.n7.nabble.com/template/NamlServlet.jtp?macro=macro_viewer&id=instant_html%21nabble%3Aemail.naml&base=nabble.naml.namespaces.BasicNamespace-nabble.view.web.template.NabbleNamespace-nabble.view.web.template.NodeNamespace&breadcrumbs=notify_subscribers%21nabble%3Aemail.naml-instant_emails%21nabble%3Aemail.naml-send_instant_email%21nabble%3Aemail.naml> 
>>>
>>
>





--
View this message in context: http://jsr166-concurrency.10961.n7.nabble.com/Single-threaded-ForkJoinPool-tp13232p13251.html
Sent from the JSR166 Concurrency mailing list archive at Nabble.com.
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://cs.oswego.edu/pipermail/concurrency-interest/attachments/20160208/b58f4e55/attachment.html>


More information about the Concurrency-interest mailing list