Java Threads, 3e by Scott Oaks and Henry Wong The following errata were *corrected* in the 03/07 reprint: This page was updated February 16, 2007 Here's a key to the markup: [page-number]: serious technical mistake {page-number}: minor technical mistake : important language/formatting problem (page-number): language change or minor formatting problem ?page-number?: reader question or request for clarification +n: n'th paragraph from the top of the page -n: n'th paragraph from the bottom of the page ######################################## {42} -1 Similarly, every time the variable is written, the value must be stored in main memory. Since these operations are atomic, we can avoid the race condition in our example by marking our done flag as volatile. -> Similarly, every time the variable is written, the value must be stored in main memory. Furthermore, Java specifies that the load and store operations are atomic for volatile variables, even for long and double variables. Hence, we can avoid the race condition in our example by marking our done flag as volatile. ######################################## {59} +5 The isHeldByCurrentThread() method is used to determine if the thread is owned by the current thread, -> The isHeldByCurrentThread() method is used to determine if this lock is owned by the current thread, ######################################## {82} -2 We've already seen that in one case the answer is yes: you can use the volatile keyword for an instance variable (other than a double or long). -> We've already seen that in one case the answer is yes: you can use the volatile keyword for an instance variable. ######################################## (85) first thread execution sequence, last line Thread1: Set currentScore == 0 -> Thread1: Set currentScore = 0 ######################################## (85) second thread execution sequence, line 3 Thread2: See if currentScore == 0 -> Thread2: See if currentScore = 0 ######################################## {87} +2 Of course, the balance is very one sided; volatile variables can be safely used only for a single load or store operation and can't be applied to long or double variables. These restrictions make the use of volatile variables uncommon. -> Of course, the balance is very one sided; volatile variables can be safely used only for a single load or store operation. This restriction makes the use of volatile variables uncommon. ######################################## <111> under "Critical Section" A critical section is a synchronized method or block. Critical sections do not nest like synchronized methods or blocks. -> A critical section is a synchronized method or block. It is provided by Windows as a lightweight version of a lock. ######################################## (112) +3 The Semaphore class keeps tracks of... -> The Semaphore class keeps track of... ######################################## {129} The newCondition() method, does public Condition newCondition( ) { return new DeadlockDetectingCondition(this); -> public Condition newCondition( ) { return new DeadlockDetectingCondition(this, super.newCondition( )); ######################################## (142) Summary table, row 1, column 1 Deadlock-detecting Lock -> Deadlock-detecting Lock (example 1) ######################################## (142) Summary table, row 2, column 1 Alternate Deadlock-detecting Lock -> Alternate Deadlock-detecting Lock (example 2) ######################################## (142) Summary table, row 1, column 2 javathreads.examples.ch06.example1.DeadlockDetectingLock -> javathreads.examples.ch06.DeadlockDetectingLock ######################################## (142) Summary table, row 2, column 2 javathreads.examples.ch06.example2.AlternateDeadlockDetectingLock -> javathreads.examples.ch06.AlternateDeadlockDetectingLock ######################################## (149) run() method at bottom of page public void run( ) { // Simulate connecting to server for (int i = 0; i < stateMessages.length; i++) { setText(stateMessages[i]); try { Thread.sleep(5 * 1000); } catch (InterruptedException ie) {} if (Thread.currentThread( ).isInterrupted( )) return; } -> public void run( ) { // Simulate connecting to server for (int i = 0; i < stateMessages.length; i++) { setText(stateMessages[i]); try { Thread.sleep(5 * 1000); } catch (InterruptedException ie) {} if (Thread.currentThread( ).isInterrupted( )) return; } ######################################## (161-162) code at bottom of page public void fireNewCharacter(CharacterSource source, int c) { CharacterEvent ce = new CharacterEvent(source, c); Enumeration e; synchronized(listeners) { e = listeners.elements( ); while (e.hasMoreElements( )) { ((CharacterListener) e.nextElement( )).newCharacter(ce); } } } -> public void fireNewCharacter(CharacterSource source, int c) { CharacterEvent ce = new CharacterEvent(source, c); Enumeration e; synchronized(listeners) { e = listeners.elements( ); while (e.hasMoreElements( )) { ((CharacterListener) e.nextElement( )).newCharacter(ce); } } } ######################################## (217) checkLicense() method in middle of page // If we got a result, we know that the license has expired JOptionPane.showMessageDialog(null, "Evaluation time period has expired", "Expired", JOptionPane.INFORMATION_MESSAGE); -> // If we got a result, we know that the license has expired JOptionPane.showMessageDialog(null, "Evaluation time period has expired", "Expired", JOptionPane.INFORMATION_MESSAGE); ######################################## (235) handleClient() method at bottom of page protected void handleClient(SelectionKey key) throws IOException { SocketChannel sc = (SocketChannel) key.channel( ); ClientInfo ci = (ClientInfo) allClients.get(sc); -> protected void handleClient(SelectionKey key) throws IOException { SocketChannel sc = (SocketChannel) key.channel( ); ClientInfo ci = (ClientInfo) allClients.get(sc); ######################################## (307) Summary table, row 2, column 1 (example 4) Table Generator (Handling reduction variables) -> Table Generator (Handling storeback variables) ########################################