The Artima Developer Community
Sponsored Link

Computing Thoughts
Java Threads
by Bruce Eckel
September 8, 2005
Summary
In my research for the "Concurrency" chapter for Thinking in Java 4e, I've read through a lot of material. This morning, I started perusing the 3rd edition of "Java Threads" by Oaks & Wong, from O'Reilly.

Advertisement

The promising thing about this book is that it focuses exclusively on the new threading material in J2SE5. A number of Java books that have appeared recently, promising to be a thorough coverage of J2SE5, have not delivered on their promises, at least where threading is concerned.

The third edition of the Oaks and Wong book appears to be a significant improvement over the first two editions. As I said, I've only just dipped into it, but so far there are two issues that I haven't been able to sort out, and I thought that perhaps readers of this weblog could offer clarifications:

The first is on page 10:

Worse yet, the word processor may periodically perform an autosave, which invariably interrupts the flow of typing and disrupts the thought process. In a threaded word processor, the save operation would be in a separate thread so that it didn't interfere with the work flow.

Hmm. I use Word for book creation (don't bother commenting about that; I've heard all the "you should use this" comments, and every one of them would require much more work to use than Word does. And OpenOffice, much as I love the concept, won't handle a book. When I find a truly better solution, I'll be the first to switch.). I've used it for many years, and although it appears to do a background save, any typing that you do during any kind of save (foreground or background) simply fills up the input buffer. That is, the operating system saves your keystrokes, but Word doesn't appear to start a separate task to perform the save.

After giving it some thought, I began to wonder if it would even be a feasible approach. In order to allow a background save to occur, I would think that you would have to clone your document and save the clone. If you started performing a save on a big document and that document was changing during the save, well, that sounds like it opens up a lot of awfully messy possibilities, especially if a complex document format could cause changes throughout the document.

So this worried me, but never having written an editor or word processor I'll grant the possibility that it's something I don't understand well enough.

But then, I came to their discussion of the volatile keyword on pages 41-43. Although volatile has always seemed trivial, in the last few years it has gotten much more complex (primarily because of a deeper understanding that has been developed about the interaction of caches and concurrency), so I was hoping to find some illumination in this book.

Instead, on page 43, I found this statement:

For example, operations like increment and decrement (e.g., ++ and --) can't be used on a volatile variable because these operations are syntactic sugar for a load, change, and a store.

My first impression was that the word "can't" meant that the compiler wouldn't let you do it, so I tried this:


public class VolatileIncrement {
  volatile int x = 1;
  public void f() { x++; }
  public String toString() { return Integer.toString(x); }
  public static void main(String[] args) {
    VolatileIncrement vi = new VolatileIncrement();
    vi.f();
    System.out.println(vi);
  }
}

The compiler had no complaints, and running the program produces a value of "2" so I must now assume that "can't" means "shouldn't" or "doing so won't give you the right results." But this is still unclear, because earlier in the paragraph they introduced the idea of atomicity:

They [volatile variables] can be used only when the operations that use the variable are atomic, meaning the methods that access the variable must use only a single load or store.

And again, I'm confused by the wording "can be used only," since clearly the operations available for a volatile variable include those that are non-atomic. In fact, no operations on long or double variables are atomic, and yet I can write this:


public class NonAtomic {
  volatile long a = 1;
  volatile double b = 1.0;
  public void f1() { a++; }
  public void f2() { b += 1.0; }
  public String toString() { 
    return Long.toString(a) + " " + Double.toString(b); 
  }
  public static void main(String[] args) {
    NonAtomic na = new NonAtomic();
    na.f1();
    na.f2();
    System.out.println(na);
  }
}

Again, no complaints from the compiler, and reasonable results at run time. So I don't really know what to think here: either they were speaking imprecisely, and meant that you shouldn't (but even then their explanation of volatile is vague at best), or they thought that you really couldn't but never actually tried it (which would be rather ominous for the rest of the book).

The section concludes in the second-to-last paragraph on page 43 with this:

The requirements of using volatile variables seem overly restrictive. Are they really important? This question can lead to an undending debate. For now, it is better to think of the volatile keyword as a way to force the virtual machine not to make temporary copies of a variable.

Two things bother me about this. The first is the suggestion that this is the subject of unending debate. My impression so far is that it is a fairly deterministic issue, but if it is really debateable I'd like to hear what the issues are (it was not clear to me from this book).

The second, and deeper, disturbance about the above statement is that my pre-new-memory-model understanding of volatile has always been "don't make any assumptions about this value when doing optimizations." That is, the optimizer might come along and look at the code surrounding a variable access and say "hey, there's nothing in this code that has changed that variable since the last code that accessed it, so I'll keep it in a register and just read from the register instead of going all the way back to main memory to access it." Ignoring the caching issue for now, volatile says "don't do that. Always read the variable as if some other process had changed it.

I suppose you could say that "putting the value of a variable in a register or a cache" could be called "making a temporary copy," but that seems imprecise to me; I think of a temporary as an actual variable that might, for example, be created by the compiler in order to evaluate a complex expression.

But I guess the real problem I'm having, after hardly getting into the book at all, is that I can't figure out whether what they're saying is wrong or whether they are just communicating it badly. But in either case it's starting to look like it will take a lot of effort to extract value from this particular book.

Any illumination is appreciated.

Talk Back!

Have an opinion? Readers have already posted 36 comments about this weblog entry. Why not add yours?

RSS Feed

If you'd like to be notified whenever Bruce Eckel adds a new entry to his weblog, subscribe to his RSS feed.

About the Blogger

Bruce Eckel (www.BruceEckel.com) provides development assistance in Python with user interfaces in Flex. He is the author of Thinking in Java (Prentice-Hall, 1998, 2nd Edition, 2000, 3rd Edition, 2003, 4th Edition, 2005), the Hands-On Java Seminar CD ROM (available on the Web site), Thinking in C++ (PH 1995; 2nd edition 2000, Volume 2 with Chuck Allison, 2003), C++ Inside & Out (Osborne/McGraw-Hill 1993), among others. He's given hundreds of presentations throughout the world, published over 150 articles in numerous magazines, was a founding member of the ANSI/ISO C++ committee and speaks regularly at conferences.

This weblog entry is Copyright © 2005 Bruce Eckel. All rights reserved.

Sponsored Links



Google
  Web Artima.com   

Copyright © 1996-2017 Artima, Inc. All Rights Reserved. - Privacy Policy - Terms of Use - Advertise with Us