Java Threads, 2ed by Scott Oaks and Henry Wong Following are the changes made in the 12/99 reprint: {16} In the 6th line of the code example, change boolean shouldRun; // Set to false to stop thread to: volatile boolean shouldRun; // Set to false to stop thread (17) After the paragraph that concludes: much like the state it would be in if the thread were waiting for I/O to occur. the following sentence was added: See Appendix A for a discussion of the volatile keyword. {29} In the 2nd line of the code example, change boolean shouldRun; // Set to false to stop thread to: volatile boolean shouldRun; // Set to false to stop thread {30} In the 6th line of the code example, change boolean shouldRun; // Set to false to stop thread to: volatile boolean shouldRun; // Set to false to stop thread {47} In the last paragraph, change the phrase making the method atomic to: serializing access to the method (52) After the paragraph that concludes: will contain the bits set by the second thread. the following sentence was added: However, atomicity does not insure thread communication; see the discussion of volatile in Appendix A. {83} In the 20th line of the code example, change private boolean done = false; to: private volatile boolean done = false; {103} In the 8th line of the code example, change boolean shouldStop = false; to: volatile boolean shouldStop = false; {110} In the 7th-10th line of the code example, change private byte result[]; // Buffer private int reslen; // Buffer length private boolean EOF; // End-of-file indicator private IOException IOError; // I/O exceptions to: private volatile byte result[]; // Buffer private volatile int reslen; // Buffer length private volatile boolean EOF; // End-of-file indicator private volatile IOException IOError; // I/O exceptions {114} In the 4th-7th line of the code example, change private byte result[]; // Buffer private int reslen; // Buffer length private boolean EOF; // End-of-file indicator private IOException IOError; // I/O exceptions to private volatile byte result[]; // Buffer private volatile int reslen; // Buffer length private volatile boolean EOF; // End-of-file indicator private volatile IOException IOError; // I/O exceptions {159} In the 6th line of the code example, change boolean shouldRun = false; to: volatile boolean shouldRun = false; {162} In the 6th line of the code example, change boolean shouldRun = false; to: volatile boolean shouldRun = false; {170} The last line of the code example, change boolean shouldRun = true; to: volatile boolean shouldRun = true; {180} On the 5th line of the code example, change public boolean shouldRun = false; to: public volatile boolean shouldRun = false; {277} On the 5th line of the code example, change boolean shouldStop = false; to: volatile boolean shouldStop = false; {285} On the 1st line of the code example, change public boolean shouldRun; to: public volatile boolean shouldRun = true; (303) The following was added to the bottom of the page: The Volatile Keyword As we mentioned in Chapter 3, the act of setting the value of a variable (except for a long or a double) is atomic. That means there is generally no need to synchronize access simply to set or read the value of a variable. However, Java's memory model is more complex than that statement indicates. Threads are allowed to hold the values of variables in local memory (e.g. in a machine register). In that case, when one thread changes the value of a variable, another thread may not see the changed value. This is particularly true in loops that are controlled by a variable (like the shouldRun variable that we use to terminate threads): the looping thread may have already loaded the value of the variable into a register and will not necessarily notice when another thread sets that variable to false. There are many ways to deal with this situation. You can synchronize on the object that contains the control variable -- or better yet, you can provide accessor methods for the control variable (such as we do with the busyflag variable in our BusyFlag class). Or you can mark the variable as volatile, which means that every time the variable is used, it must be read from main memory. In versions of the VM through 1.2, the actual implementation of Java's memory model made this a moot point: variables were always read from main memory. But as VMs become more sophisticated, they will introduce new memory models and optimizations, and observing this rule will be increasingly important. (319) The following index entry was added: volatile, 303