Sunday, August 12, 2007

NFJS: The Java Memory Model

[More of my first "No Fluff, Just Stuff" experience]

The Java Memory Model session with Brian Goetz was intense, and I wasn't the only attendee to come away from the talk feeling that way. I'm still trying to absorb some of the concepts mentioned in the session, but I will do my best to summarize it here.

"A Memory Model is an abstraction for how one thread sees the effects of another thread's actions on memory." The following optimizations may interfere with this visibility
  • Values might be sitting in a processor-local cache and not yet flushed, or the local processor may have stale values in its cache
  • Values could be cached in registers and not written to memory
  • The processor may have executed instructions out of order
  • The compiler may have reordered certain instructions
The problem with these optimizations comes when you are trying to access shared data.

What blew the minds of some of the attendees was the idea that "sequentiality is an illusion" with modern processors. "This is not your father's Von Neumann machine," as Brian put it. But Java does provide the developer with mechanisms to ease the pain.

Synchronize

The synchronize mechanism is one of the tools Java provides to help developers deal with the complexities of concurrent programming. Here is Brian's Rule of Synchronization
If you are writing a field which may next be read by another thread, or reading a field which may have been last written by another thread, you must synchronize.
  • Synchronization is required by both the reading thread and the writing thread
  • Both reading and writing threads must synchronize on the same lock
In essence you must synchronize when accessing shared, mutable data. Something else that Brian mentioned that probably should be a global rule of programming is "make it right before you make it fast." (Hey, that rule could apply to guitar playing as well!)

Brian then talked about the happens-before relation which states that "if one action happens-before another, then the first is visible to and ordered before the second. This relation is defined in the Java Language Specification (Chapter 17).

So what problems could arise if the Java Memory Model (JMM) did not have the happens-before rule? The optimizations listed above will give you a clue. The order of operation execution in thread A, for example, may appear different from thread B's perspective (just like Special Relativity – order of execution is relative to the observer). Essentially, operations could occur in almost any order.

Volatile

The other tool that Java developers have for dealing with concurrent programming complexities is volatile variables. The visibility rules are similar to synchronized blocks, but there are no atomicity or mutual exclusion guarantees. Volatile variables are good for flags and "for safely publishing objects where atomicity is not required."

There is a lot more in this session including a little history of the JMM, problems with the old JMM, the double-checked-locking problem and how the new JMM fixes it with volatile. He ends with the following advice
  • Don't try to reason about ordering in under-synchronized programs
  • Make it right, then make it fast
  • Avoid tricks which rely on unsynchronized nonvolatile reads, like double-checked locking
  • Don't try to outsmart the JVM (synchronization is trickier than you might think)
Like I said, this session was intense. There were people who seemed visibly amazed at some of the things Brian was telling them (myself included). I think another idea from Einstein applies: spooky action at a distance. Spooky indeed.

A note on the speaker: Brian is a good speaker and very knowledgeable. He was obviously the smartest person in the room. He did a very good job explaining something that is very complex which tells me he really understands this subject.

Next up: The Holy Grail(s)

No comments: