New wiki page: Concurrency in JRuby

Questions about JRuby and concurrency come up a lot, so I wrote up a
quick wiki page summarizing thread safety, volatility, and atomicity
in JRuby, along with some patterns to look out for and options for
doing them right.

Feel free to add, or let me know if you have questions.

  • Charlie

I get a 404. Link not right?

Cheers,
–Bob

On Sat, Dec 17, 2011 at 4:26 PM, Charles Oliver N.

Wow, I’m a genius. Too many things floating in my paste buffer.

  • Charlie

On Sun, Dec 18, 2011 at 9:29 PM, Yoko H. [email protected] wrote:

On Sat, Dec 17, 2011 at 7:47 PM, Charles Oliver N.
[email protected] wrote:

Concurrency in jruby · jruby/jruby Wiki · GitHub

Really nice page.

I need to find time for re-implementing Hash to make it thread-safe.

At the very least, we should try to wrap error-producing sections in
bounds/null checks so they can raise Ruby errors, like RubyArray does.

I’d love to have a threadsafe Hash implementation if it doesn’t hurt
performance. I’d also love to do what you and I have talked about
before: rework RubyHash so that it can wrap any type of
java.util.Map…then it would be trivial to provide a ConcurrentHash
by simply wrapping ConcurrentHashMap.

  • Charlie

On Sat, Dec 17, 2011 at 7:47 PM, Charles Oliver N.
[email protected] wrote:

Concurrency in jruby · jruby/jruby Wiki · GitHub

Really nice page.

I need to find time for re-implementing Hash to make it thread-safe.

-Yoko

On Sat, 2011-12-17 at 18:47 -0600, Charles Oliver N. wrote:

Concurrency in jruby · jruby/jruby Wiki · GitHub

Nicely organized and written Charles.

“… the following operations are threads-safe in JRuby:” goes on to
describe numerous race conditions under easily encountered scenarios.
Is “thread safe” not contradicted here? If not, a bit more explanation
is needed IMO.

“A given autoload is only allowed to run in a single thread:” On jruby
1.6.x I’m bitten by this all the time in Sinatra apps. From jira, I had
the impression that this was only fixed (safe) in 1.9 mode? I currently
work around it by manually loading things my code doesn’t directly use,
just to avoid autoload related errors in the application threads later.

–David

On Sun, Dec 18, 2011 at 10:54 PM, David K. [email protected]
wrote:

Nicely organized and written Charles.

“… the following operations are threads-safe in JRuby:” goes on to
describe numerous race conditions under easily encountered scenarios. Is
“thread safe” not contradicted here? If not, a bit more explanation is
needed IMO.

Subbu questioned this as well. I’ll move the discussion of races to a
separate paragraph with more details.

“A given autoload is only allowed to run in a single thread:” On jruby
1.6.x I’m bitten by this all the time in Sinatra apps. From jira, I had the
impression that this was only fixed (safe) in 1.9 mode? I currently work
around it by manually loading things my code doesn’t directly use, just to
avoid autoload related errors in the application threads later.

Nahi clarified this in his post and edited the wiki. Thanks for
bringing it to our attention…I sometimes forget what is and is not
in 1.6, working on master all the time.

  • Charlie

Hi,

(2011/12/19 13:54), David K. wrote:

“A given autoload is only allowed to run in a single thread:” On jruby
1.6.x I’m bitten by this all the time in Sinatra apps. From jira, I had
the impression that this was only fixed (safe) in 1.9 mode? I currently
work around it by manually loading things my code doesn’t directly use,
just to avoid autoload related errors in the application threads later.

The fix for autoload is from JRuby 1.7 which is not out yet, in both
1.8/1.9 modes. I’ll update the wiki.

// NaHi

This is good information.

For users such as (project vert.x) we guarantee that JRuby code is
always executed by the same thread (event loop), so we don’t need it to
be threadsafe. I’m actually more interested that stuff is not made
volatile, since, aiui volatile writes cause a flush even if there are no
other reads, and hence incur a performance penalty.

Looking at the wiki page it seems most instance operations aren’t
volatile so I think we should be ok. I’m be more concerned if heavily
used classes such as Hash were made thread-safe.

Would it be possible to have someway of telling JRuby that it’s being
run in single threaded mode (I think Rhino does something like this),
and if so, then it didn’t use the thread-safe versions of classes?

On Mon, Dec 19, 2011 at 2:17 AM, Tim F. [email protected] wrote:

This is good information.

For users such as (project vert.x) we guarantee that JRuby code is always
executed by the same thread (event loop), so we don’t need it to be
threadsafe. I’m actually more interested that stuff is not made volatile,
since, aiui volatile writes cause a flush even if there are no other reads,
and hence incur a performance penalty.

Somewhat. Volatile writes on the JVM (into “volatile” fields) should
only impact the cache line where a given core is caching the given
field’s value. It’s not a full cache flush by any means. There’s
certainly a performance hit, but it’s not catastrophic.

Looking at the wiki page it seems most instance operations aren’t volatile
so I think we should be ok. I’m be more concerned if heavily used classes
such as Hash were made thread-safe.

Before writing this document up, I actually did some experiments to
make instance variables volatile: Two attempts to make instance vars volatile. The ARA version is 10-15% slower, and Unsafe version is 5-10% slower. · GitHub

They both worked and both carried with them the expected performance
hit, but that hit was not as bad as I expected (5-15% for a
variable-heavy benchmark). It’s still too high for me to force it on
all objects in JRuby, of course.

What we may do, instead, is offer a special Struct type or Ruby
superclass that guarantees its instance variables are always volatile,
perhaps by requiring the class creation explicitly state the variables
it will use. That would likely be sufficient for volatility-sensitive
thread programming.

Would it be possible to have someway of telling JRuby that it’s being run in
single threaded mode (I think Rhino does something like this), and if so,
then it didn’t use the thread-safe versions of classes?

I think you’ll find that in practice, the thread-safety mechanisms we
use won’t impact steady-state performance. The “write” perf impact is
limited to modifying class-level data like method tables, constants,
and class variables…all ideally happening only at boot time. The
“read” perf impact is mitigated by our various caching strategies,
which avoid hitting volatile structures and locks unless the cache
must be invalidated.

If you get to a point where you think you’re seeing unreasonably poor
multi-thread scaling, we can explore that further. Until then, I think
you’ll be ok with thread-safety guarantees always on.

  • Charlie