|
Surprises in the Memory Model
The sample shown in listing 1 was one of the surprises of memory
model. There are a few more, which are interesting. The Java
language specification assures us that strings are immutable, so
most operations on a string destroy the original object and
create a new one. But in reality the compiler can optimize the
operation and reuse the same memory as the original string. For
instance we have a string ‘String stringSample =
"javaboutique";’ stored in memory at memory location m1. The
compiler will store this String in memory as origin location =
m1 and offset = 12. Now when an operation ‘stringSample =
stringSample.substring(4);’ is done, stringSample will contain
"boutique". As per the Java specification we would assume that
stringSample will be moved to a new location m2 and the old
memory location is left for the garbage collector, but compilers
can reuse the same memory location and update the offsets. So
the new string after the sub string operation would read as
origin location = m1+4 and offset = 8. This does not break the
Java specification, as the old reference is lost and a new
reference is created with a new origin location and a new
offset. The problem is when two threads try to access this
string at the same time; the second thread might get the wrong
starting location. Synchronizing these methods would alleviate
the problem.
Final Fields
Java provides for final fields, which are initialized once and
are never changed for the life of the object instance. Unlike
normal fields, compilers can cache final fields into registers
and read from there without reloading them from memory again. In
the case of normal fields values can be cached into registers
but need to be synchronized with the value in memory when a read
is done.
Final fields are of great value in multi-threaded environments as
programmers can use them as thread safe immutable objects, which
do not need synchronization. Since an immutable field cannot be
modified there is a guarantee that the field will not behave
erratically even in a data race condition.
Final fields can be initialized either directly in the class
when they are declared or through the constructor of the class.
According to the Java specification an object is deemed as
completely initialized only when the constructor of the class
has completed execution. Since the final variables are
initialized in the constructor there is a guarantee that the
final field is initialized and available to threads with the
correct value. The Java memory model ensures that threads get
access to final fields only after the object is completely
initialized. The Java memory model ensures this by freezing the
final field when the constructor for the class exits normally.
In the case of constructors calling their super classes final
field freeze takes place when the last invoked constructor exits
normally.
A final field is considered unchangeable after it is first
initialized to a value, but there could be situations when a
final field needs to be modified after it is created. One of the
situations is during deserialization (reverse of serialization).
During deserialization the system will need to change the value
of a final field after it has been initialized and frozen.
During deserialization the object is created first and then the
field values are set. In this case the freeze on a final field
occurs only after the constructor has exited and the final
fields have been set. So the object should be made unavailable
to all threads till the final fields have been set into the
object.
Conclusion
The JSR 133 (Java Memory model and thread specification) is not
intended as enhancement JSR or a new feature. The memory Model
spec should be seen as an addendum to the original Java language
specification. The specification does not introduce any new
concepts or provide new functionality but serves more like a
clarification to the original Java specification. Though a good
effort has been made to clarify how threads work and how memory
operates, the specification still leaves some questions
unanswered. Most of the unanswered questions are centered on how
compilers make optimizations to programs and order instructions
within a program and how these changes affect the memory. The
individual JVM implementers best answer these questions, as they
are the ones who use these optimizations within the JVM. Though
the specification does not clearly state how the threads are
handled in individual JVM implementations, it provides details
on what a programmer can expect when dealing with threads.
Benoy Jose is a web
developer with over six years of experience in J2EE and
Microsoft technologies. He is a Sun Certified programmer and
enjoys writing technical and non-technical articles for various
magazines.
New on the Java Boutique:
New Review:
Time Management Made Easy with the Quartz Enterprise Job Scheduler
Why not just use the Java timer API? This open source scheduling
API boasts simplicity, ease-of-integration, a well-rounded feature
set, and it's free!
New Applet:
Reverse Complement
Reverse Complement is a simple applet that converts DNA or RNA
sequences into three useful formats.
Elsewhere on internet.com:
WebDeveloper Java
Lots of Java information on webdeveloper.com
WDVL Java
Thorough Java resource at the Web Developer's Virtual Library.
ScriptSearch Java
Hundreds of free Java code files to download.
jGuru: Your View of the Java Universe
Customizable portal with online training, FAQs, regular news updates, and tutorials.
|