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

Josh Humphries jh at squareup.com
Mon Dec 1 18:23:33 EST 2014


A future probably won't do since it's single use, but for this case,
control needs to keep swapping between consumer and co-routine and back. I
wonder if a there's a way to get a Phaser to work (plus a volatile field to
actually store the item being transferred).

I've actually toyed with exactly this sort of thing, emulating
generators/co-routines in Java using multiple threads. My experiments used
a SynchronousQueue, and it was painfully slow. BTW, it seems like one issue
with ArrayBlockingQueue(1) is that it's not a perfect exchange. You can
have a single element in the queue, unconsumed, instead of a synchronous
hand-off. I think that means that the generator thread is always one ahead
of the consumer thread. (Although maybe I'm imagining the rest of your
implementation incorrectly. And perhaps this fact doesn't strictly matter.)


----
*Josh Humphries*
Manager, Shared Systems  |  Platform Engineering
Atlanta, GA  |  678-400-4867
*Square* (www.squareup.com)

On Mon, Dec 1, 2014 at 5:41 PM, Martin Buchholz <martinrb at google.com> wrote:

> If all you want to do is to have one thread produce a single result
> while another waits, that sounds a lot like Future, and both recent
> FutureTask and CompletableFuture ought to be more efficient than a
> 1-element ABQ.
>
> On Mon, Dec 1, 2014 at 2:34 PM, Charles Oliver Nutter
> <headius at headius.com> wrote:
> > Ahh yes, that's another one I tried. Sadly it was *also* still slower
> > than using a single-element ArrayBlockingQueue.
> >
> > I will try to explore the options again and report back, so I know
> > I've got my facts straight.
> >
> > - Charlie
> >
> > On Mon, Dec 1, 2014 at 3:02 PM, Vitaly Davidovich <vitalyd at gmail.com>
> wrote:
> >> Have you tried SynchronousQueue for the handoff?
> >>
> >> On Mon, Dec 1, 2014 at 3:17 PM, Charles Oliver Nutter <
> headius at headius.com>
> >> 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?
> >>>
> >>> Thanks for clarifying things :-)
> >>>
> >>> - Charlie
> >>>
> >>> On Mon, Dec 1, 2014 at 2:02 PM, Martin Buchholz <martinrb at google.com>
> >>> wrote:
> >>> > On Mon, Dec 1, 2014 at 11:50 AM, Charles Oliver Nutter
> >>> > <headius at headius.com> wrote:
> >>> >> I'm working to narrow that down now. You're right...I don't expect
> to
> >>> >> have found a bug, but I'm having trouble explaining the behavior I'm
> >>> >> seeing.
> >>> >>
> >>> >> Just to clarify the key point, though: LockSupport.park should be
> 100%
> >>> >> wakeable using Thread#interrupt, yes? There's no situation where a
> >>> >> thread in park would *not* be expected to wake up in response to
> >>> >> Thread#interrupt?
> >>> >
> >>> > Right - park() is allowed to return spuriously, but not allowed to
> >>> > spuriously fail to return !
> >>> > But these methods are usually called in a loop, and if a caller
> failed
> >>> > to check or notice the interrupt then it would call park again.
> >>> _______________________________________________
> >>> Concurrency-interest mailing list
> >>> Concurrency-interest at cs.oswego.edu
> >>> http://cs.oswego.edu/mailman/listinfo/concurrency-interest
> >>
> >>
> _______________________________________________
> Concurrency-interest mailing list
> Concurrency-interest at cs.oswego.edu
> http://cs.oswego.edu/mailman/listinfo/concurrency-interest
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://cs.oswego.edu/pipermail/concurrency-interest/attachments/20141201/6c8e831b/attachment.html>


More information about the Concurrency-interest mailing list