Newsletter sign-up
View all newsletters

Enterprise Java Newsletter
Stay up to date on the latest tutorials and Java community news posted on JavaWorld

Sponsored Links

Optimize with a SATA RAID Storage Solution
Range of capacities as low as $1250 per TB. Ideal if you currently rely on servers/disks/JBODs

Java 101: Understanding Java threads, Part 4: Thread groups, volatility, and thread-local variables

Final concepts for improving Java application programming with Java threads

  • Print
  • Feedback

Page 6 of 8

Volatility

Volatility, that is, changeability, describes the situation where one thread changes a shared field variable's value and another thread sees that change. You expect other threads to always see a shared field variable's value, but that is not necessarily the case. For performance reasons, Java does not require a JVM implementation to read a value from or write a value to a shared field variable in main memory, or object heap memory. Instead, the JVM might read a shared field variable's value from a processor register or cache, collectively known as working memory. Similarly, the JVM might write a shared field variable's value to a processor register or cache. That capability affects how threads share field variables, as you will see.

Suppose a program creates a shared integer-field variable x whose initial value in main memory is 10. This program starts two threads; one thread writes to x, and the other reads x's value. Finally, this program runs on a JVM implementation that assigns each thread its own private working memory, meaning each thread has its own private copy of x. When the writing thread writes 6 to x, the writing thread only updates its private working-memory copy of x; the thread does not update the main-memory copy. Also, when the reading thread reads from x, the returned value comes from the reading thread's private copy. Hence, the reading thread returns 10 (because a shared field variable's private working-memory copies initialize to values taken from the main-memory counterpart), not 6. As a result, one thread is unaware of another's change to a shared field variable.

A thread's inability to observe another thread's modification to a shared field variable can cause serious problems. For example, last month's YieldDemo application contained a pair of shared field variables: finished and sum. For JVMs that support separate working memory for each thread, the main and main-created YieldDemo threads can have their own copies of finished and sum. As a result, the main thread's execution of finished = true; would not affect the YieldDemo thread's copy of that variable—and the YieldDemo thread would never terminate.

When you ran YieldDemo, you probably discovered that program eventually terminated. That implies your JVM implementation reads/writes main memory instead of working memory. But if you found that the program did not terminate, you probably encountered a situation where the main thread set its working memory copy of finished to true, not the equivalent main-memory copy. Also, the YieldDemo thread read its own working-memory copy of finished, and never saw true.

To fix YieldDemo's visibility problem (on those JVMs that support working memory), include Java's volatile keyword in the finished and sum declarations: static volatile boolean finished = false; and static volatile int sum = 0;. The volatile keyword ensures that when a thread writes to a volatile shared field variable, the JVM modifies the main-memory copy, not the thread's working-memory copy. Similarly, the JVM ensures that a thread always reads from the main-memory copy.

  • Print
  • Feedback

Resources
  • Learn more about Java: See the complete listing for Jeff Friesen's Java 101 series -- archived on JavaWorld.
  • Also see the Java Tips series: More than five years of compiled tips from JavaWorld's expert readers.