[concurrency-interest] ArrayBlockingQueue (and possibly others) not waking on interrupt?

David M. Lloyd david.lloyd at redhat.com
Mon Dec 1 17:12:51 EST 2014


On 12/01/2014 02:17 PM, Charles Oliver Nutter wrote:
> Sense and sanity prevail! Given the new information that this is
> probably my fault, I dug a bit deeper...and found a race within my own
> code. The thread interrupt logic in JRuby was firing before an
> unblocker function was installed, causing the interrupt to just set
> flags and not forcibly interrupt the thread. The blocking call then
> proceeded and the flags were not checked again until after it had
> completed. Fixed it by adding a second flag check *after* the
> unblocker has been set but *before* making the blocking call, and it
> seems solid now.
>
> Incidentally, I have a question...
>
> This logic is being used to emulate fibers (coroutines) in JRuby. A
> fiber belongs to a given thread, and there may be many active fibers
> within a thread, but none of them run concurrently. Every transfer
> into a fiber is an explicit hand-off. If you're familiar with Python
> generators or Go's goroutines, you get the idea. I've struggled to
> find the right data structure to efficiently implement this hand-off.
>
> * Exchanger was just about the slowest way. I never figured out why.
> * Manually implementing it with park/unpark worked, but I could never
> get it perfect. Might have been this race or another race, so I may
> revisit.
> * new ArrayBlockingQueue(1) ultimately ended up being the fastest by a
> wide margin.
>
> I believe I've asked this before, but what's the fastest way to
> *explicitly* transfer control to another thread in an interruptible
> way?

I think probably writing a work item to a thread-specific field and 
unparking the thread must be the fastest possible way to give a specific 
waiting thread some specific work.  I don't think that unpark does 
anything in terms of memory visibility though (in any event I'm not 
seeing anything in the javadoc for LockSupport) so the field probably 
would have to be volatile for this to work in its simplest form. 
Tracking and deciding which among multiple threads (if you have more 
than one in a pool situation) are ready for work adds a bunch of 
complexity though, as does coping with having no workers available (e.g. 
do you make the producer wait, or employ a pending tasks queue?). 
Follow this path a surprisingly short distance and you're facing the 
same problems that ThreadPoolExecutor attempts to solve.

-- 
- DML


More information about the Concurrency-interest mailing list