Java Memory Model: down to the metal
Javapolis is over, and among the sessions that can be seen and heard online, there's Brian Goetz's on the here so you may want to refer to these resources for further details.
The short story is that those keywords now impose memory barriers, i.e. they tell the processors to flush the caches to main memory, or to invalidate the caches and therefore read fresh data from main memory.
In JDK 1.4, the synchronized keyword does not guarantee a memory barrier when the lock is released. In JDK 5 the memory barrier is guaranteed. (Now, you may think that in JDK 5 the double checked locking code above works fine, but it does not - not yet).
Now that we are done with the preamble, let's go back to my original question: how are these memory barriers implemented in the JVM ?
It turns out operative systems do not have primitives (system calls) that handle memory barriers, but processors do. So the JVM goes down to the metal, from C++ to assembler, and squeezes in few assembler instructions to tell the processor to perform a memory barrier.
For example to implement a particular memory barrier called fence, in a x86 the assembler instruction is lock addl 0,(sp) where sp is the stack pointer, while in a ia64 there is a dedicated assembler instruction called mf (memory fence).
Conclusion: Once again I am thankful that the JVM takes care of these details for me, although it's quite funny to figure them out :D
The short story is that those keywords now impose memory barriers, i.e. they tell the processors to flush the caches to main memory, or to invalidate the caches and therefore read fresh data from main memory.
In JDK 1.4, the synchronized keyword does not guarantee a memory barrier when the lock is released. In JDK 5 the memory barrier is guaranteed. (Now, you may think that in JDK 5 the double checked locking code above works fine, but it does not - not yet).
Now that we are done with the preamble, let's go back to my original question: how are these memory barriers implemented in the JVM ?
It turns out operative systems do not have primitives (system calls) that handle memory barriers, but processors do. So the JVM goes down to the metal, from C++ to assembler, and squeezes in few assembler instructions to tell the processor to perform a memory barrier.
For example to implement a particular memory barrier called fence, in a x86 the assembler instruction is lock addl 0,(sp) where sp is the stack pointer, while in a ia64 there is a dedicated assembler instruction called mf (memory fence).
Conclusion: Once again I am thankful that the JVM takes care of these details for me, although it's quite funny to figure them out :D