Java Threads, 3rd Edition by Scott Oaks, Henry Wong The unconfirmed error reports are from readers. They have not yet been approved or disproved by the author or editor and represent solely the opinion of the reader. 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 This page was updated February 27, 2008. UNCONFIRMED errors and comments from readers: {30} 2nd paragraph; The paragraph can easily be (mis)understood as stating that in Example 4 calling the interrupt() method results in the interrupted status being set, even if the thread is blocked by the sleep() method. However, according to the Thread API, the interrupted status is cleared when the sleep() method throws an InterruptedException. [30] bottom paragraph; "The character-reading thread still executes the sleep() method, which won't be interrupted (since the main thread has already completed the interrupt() method)". This is impossible. After interrupt() method finish, the character-reading thread throws InterruptedException in the sleep() method call. Please, see the InterruptedException in javadoc's Thread.sleep(). {36} middle; While the text states that the method interrupted() simply returns the value of Thread.currentThread().isInterrupted(), the Java API for the Thread class adds that this method also clears the interrupted status. [62] newCharacter method; 2nd paragraph of p65 says, "in the same order as the newCharacter". However, the order for getting the locks is not correct. public void newCharacter(CharacterEvent ce){ try { scoreLock.lock(); charLock.lock(); } ... ... finally { scoreLock.unlock(); charLock.unlock(); } } should be replaced by public void newCharacter(CharacterEvent ce){ try { scoreLock.lock(); charLock.lock(); } ... ... finally { charLock.unlock(); scoreLock.unlock(); } } --------------------------------------------------------------- Author's comments: The lock() method calls are all done in the beginning of the method. And the lock() method does not throw any exceptions. Hence, it is not necessary to check to see if the lock is already grabbed before unlocking it. In the finally clause, it is guaranteed that both locks are grabbed, and need to be released. The finally clause's purpose is to release both locks -- locks that are guaranteed to be owned. And it is only releasing those two locks. While it is "prettier" to release the locks in the reverse order in which they are grabbed, it is not necessary in this case. --------------------------------------------------------------- (85) 4th paragraph from the bottom; The lines Thread1: Set currentScore == 0 Thread2: See if currentScore = 0 must read Thread1: Set currentScore = 0 Thread2: See if currentScore == 0 [86] First paragraph; Prior to Java 1.5, the double-checked locking idiom in Java was broken as the author indicated in this paragraph. However, as I understood it the changes to the memory model and particularly to the sematics of volatile in Java 1.5 now allow the use of this idiom, providing that the lazily initialized object is a volatile field. I include links to articles I have recently seen regarding this for further explanation: http://www.ibm.com/developerworks/library/j-jtp03304/ http://www.cs.umd.edu/~pugh/java/memoryModel/jsr-133-faq.html#volatile The paragraph on double-checked locking should be changed to reflect this change in Java 1.5. (173) 4th paragraph; "to the executing state" should be "to the exiting state". (196) 2nd code segment; public call( ) throws Execption; should read: public call( ) throws Exception; {239} bottom half, handleClient method; The SocketChannel sc is nonblocking as it is created in the handleServer method on bottom of page 234. But the code does a sc.read(buffer) and assumes that all 8 bytes is avaiable instantly. It seemes to me that we might end up with fewer than 8 bytes.