Concurrent Programming in Java
© 1996 Doug Lea

Errata for the first printing


Corrections and Clarifications

Page 23
Replace `For example, the start method can be called again after termination to start a new activity using the same thread' with `However, stopped threads are not restartable.' [Correction to conform to JLS: Versions of the JDK from 1.02 on do not allow restart. See the Java Language Specification, p589 for more details.]
page 24
Replace `the Java run time system picks one with the highest priority' with `the Java run time system generally picks one with the highest priority in accord with the following rules' [Correction to conform to JLS: To better accommodate implementations on some operating systems, the specification does not strictly guarantee compliance with the basic priority scheduling model. However, the intent is that priorities be honored.]
Page 24
Extend `unless the variables are marked as volatile' with `or access is synchronized'. [Clarification.]
Page 29 and 315
Replace `Hansen' with `Hanson'. [Typo.]
Page 29 and 316
Replace `Tannenbaum' with `Tanenbaum'. [Typo.]
Page 69
Declare methods moveTo and shiftX as synchronized. [Clarification: Lack of synchronization needlessly invites confusion about nature of example. Even though, by the arguments in preceeding sections, synchronization is arguably unnecessary in this class as it stands, it would essentially always be needed in more realistic versions of this class containing other methods that rely on atomicity of updates to prevent inconsistent access.]
Page 86
Replace `it is that state' with `it is in that state'. [Typo.]
Page 95
Replace `BoundedCounterV1' with `BoundedCounterV0'. [Typo.]
Page 96
Replace `will run first' with `will generally run first'. [See comment about page 24.]
Page 97
Both the P() and V() methods in class CountingSemaphore should be declared as synchronized. [Inadvertent omission.]
Page 99
Replace `slower operation that' with `slower operation than'. [Typo.]
Page 105
Add comment in code example that this sets up a possible race condition. [Clarification: This is typical of code using suspend/resume, and is one of the reasons not to use them.]
Page 118
Declare loc_ as volatile. [Clarification: This makes the code conform to the advice given about classes with methods using retries.]
Page 140
Replace `empty an interface' with `an empty interface'. [Typo.]
Page 142
Replace `immtable' with `immutable' in code comment. [Typo.]
Page 210
Replace `always chosen to run' with `generally chosen to run' [See comment about page 24.]
Page 260
Replace `og' with `of' in code comment. [Typo.]
Page 302
Fix brace scope error in RWVSN.beforeRead code. [Coding error.] It should read:
  protected void beforeRead() {
    synchronized(waitingReaderMonitor_) {
      synchronized(this) { // test condition under synch
        if (allowReader()) {
          ++activeReaders_;
          return;
        }
        else 
          ++waitingReaders_;
      }
      try { waitingReaderMonitor_.wait(); } 
      catch (InterruptedException ex) {}
    }
  }
Page 308
Replace `This requires care, for example, to ensure that suspensions do not occur within synchronized code regions that would freeze up the scheduler.' with `However, it is more flexible to use wait based consructions.' [This corrects some poor guidance. Even in schedulers, the use of suspend/resume is almost always inferior to wait/notify.]
Page 308
Similarly, replace the SchedulerVSR example (which could encounter a missed signal in most contexts and is not very extensible) with the following wait-based version:
public class SchedulerVSR { // generic one-at-a-time version
  protected TaskQueue queue_ = new TaskQueue();     // fixed, unique
  protected Task running_ = null; // currently running task

  public void enter(Task t) {
    synchronized (t) {        // lock t in order to use wait below
      for (;;) {
        synchronized(this) {
          if (t == running_) 
            return;
          else if (running_ == null) {
            running_ = t;
            return;
          }
          else
            queue_.put(t);  // will be dequeued by done method
        }
         try {  t.wait(); } catch (InterruptedException ex) {}
      }
    }
  }

  public void done(Task t) {
    synchronized(this) {
      if (t != running_) 
        return; // minor safeguard
      else if (queue_.isEmpty()) {
        running_ = null;
        return;
      }
      else
        running_ = queue_.take();
    }
    synchronized(running_) { running_.notifyAll();}
  }
}
[Also note that if the monitor for the Task object is never used for any other purpose, you could change the notifyAll in to notify. You can also add code (probably to the Queue) to ensure that a Task is never enter()ed twice. ]
In addition to incorporating these, the second printing differs in a few inessential ways, for example adding Library of Congress cataloging on the copyright page and adjusting the spacing and layout of a few pages.

Thanks to David Holmes, Moti Ben-Ari, Doug Schmidt, David Hanson, Grant Woodside, Tom May, and Joseph Bowbeer for pointing out errors.

Please send any questions or comments about this book to dl@cs.oswego.edu.


Doug Lea
Last modified: Fri Jun 12 07:49:08 EDT 1998