java thread programming -- sams

375

Upload: others

Post on 12-Sep-2021

9 views

Category:

Documents


0 download

TRANSCRIPT

Page 1: Java Thread Programming -- SAMS
root
source.exe

source.tar

source/chapter02/TwoThread.java

source/chapter02/TwoThread.java

public   class   TwoThread   extends   Thread   {
     public   void  run ()   {
         for   (   int  i  =   0 ;  i  <   10 ;  i ++   )   {
             System . out . println ( "New thread" );
         }
     }

     public   static   void  main ( String []  args )   {
         TwoThread  tt  =   new   TwoThread ();
        tt . start ();

         for   (   int  i  =   0 ;  i  <   10 ;  i ++   )   {
             System . out . println ( "Main thread" );
         }
     }
}

source/chapter03/TwoThread.java

source/chapter03/TwoThread.java

public   class   TwoThread   extends   Thread   {
     private   Thread  creatorThread ;

     public   TwoThread ()   {
         // make a note of the thread that constructed me!
        creatorThread  =   Thread . currentThread ();
     }

     public   void  run ()   {
         for   (   int  i  =   0 ;  i  <   10 ;  i ++   )   {
            printMsg ();
         }
     }

     public   void  printMsg ()   {
         // get a reference to the thread running this
         Thread  t  =   Thread . currentThread ();

         if   (  t  ==  creatorThread  )   {
             System . out . println ( "Creator thread" );
         }   else   if   (  t  ==   this   )   {
             System . out . println ( "New thread" );
         }   else   {
             System . out . println ( "Mystery thread --unexpected!" );
         }
     }

     public   static   void  main ( String []  args )   {
         TwoThread  tt  =   new   TwoThread ();
        tt . start ();

         for   (   int  i  =   0 ;  i  <   10 ;  i ++   )   {
            tt . printMsg ();
         }
     }
}

source/chapter03/TwoThreadAlive.java

source/chapter03/TwoThreadAlive.java

public   class   TwoThreadAlive   extends   Thread   {
     public   void  run ()   {
         for   (   int  i  =   0 ;  i  <   10 ;  i ++   )   {
            printMsg ();
         }
     }

     public   void  printMsg ()   {
         // get a reference to the thread running this
         Thread  t  =   Thread . currentThread ();
         String  name  =  t . getName ();
         System . out . println ( "name="   +  name );
     }

     public   static   void  main ( String []  args )   {
         TwoThreadAlive  tt  =   new   TwoThreadAlive ();
        tt . setName ( "my worker thread" );

         System . out . println ( "before start(), tt.isAlive()="   +  tt . isAlive ());
        tt . start ();
         System . out . println ( "just after start(), tt.isAlive()="   +  tt . isAlive ());

         for   (   int  i  =   0 ;  i  <   10 ;  i ++   )   {
            tt . printMsg ();
         }

         System . out . println (
             "at the end of main(), tt.isAlive()="   +  tt . isAlive ());
     }
}

source/chapter03/TwoThreadGetName.java

source/chapter03/TwoThreadGetName.java

public   class   TwoThreadGetName   extends   Thread   {
     public   void  run ()   {
         for   (   int  i  =   0 ;  i  <   10 ;  i ++   )   {
            printMsg ();
         }
     }

     public   void  printMsg ()   {
         // get a reference to the thread running this
         Thread  t  =   Thread . currentThread ();
         String  name  =  t . getName ();
         System . out . println ( "name="   +  name );
     }

     public   static   void  main ( String []  args )   {
         TwoThreadGetName  tt  =   new   TwoThreadGetName ();
        tt . start ();

         for   (   int  i  =   0 ;  i  <   10 ;  i ++   )   {
            tt . printMsg ();
         }
     }
}

source/chapter03/TwoThreadSetName.java

source/chapter03/TwoThreadSetName.java

public   class   TwoThreadSetName   extends   Thread   {
     public   void  run ()   {
         for   (   int  i  =   0 ;  i  <   10 ;  i ++   )   {
            printMsg ();
         }
     }

     public   void  printMsg ()   {
         // get a reference to the thread running this
         Thread  t  =   Thread . currentThread ();
         String  name  =  t . getName ();
         System . out . println ( "name="   +  name );
     }

     public   static   void  main ( String []  args )   {
         TwoThreadSetName  tt  =   new   TwoThreadSetName ();
        tt . setName ( "my worker thread" );
        tt . start ();

         for   (   int  i  =   0 ;  i  <   10 ;  i ++   )   {
            tt . printMsg ();
         }
     }
}

source/chapter03/TwoThreadSleep.java

source/chapter03/TwoThreadSleep.java

public   class   TwoThreadSleep   extends   Thread   {
     public   void  run ()   {
        loop ();
     }

     public   void  loop ()   {
         // get a reference to the thread running this
         Thread  t  =   Thread . currentThread ();
         String  name  =  t . getName ();

         System . out . println ( "just entered loop() - "   +  name );

         for   (   int  i  =   0 ;  i  <   10 ;  i ++   )   {
             try   {
                 Thread . sleep ( 200 );
             }   catch   (   InterruptedException  x  )   {
                 // ignore
             }

             System . out . println ( "name="   +  name );
         }

         System . out . println ( "about to leave loop() - "   +  name );
     }

     public   static   void  main ( String []  args )   {
         TwoThreadSleep  tt  =   new   TwoThreadSleep ();
        tt . setName ( "my worker thread" );
        tt . start ();

         // pause for a bit
         try   {
             Thread . sleep ( 700 );
         }   catch   (   InterruptedException  x  )   {
             // ignore
         }

        tt . loop ();
     }
}

source/chapter04/SecondCounter.java

source/chapter04/SecondCounter.java

import  java . awt . * ;
import  javax . swing . * ;
import  java . text . * ;

public   class   SecondCounter   extends   JComponent   implements   Runnable   {
     private   volatile   boolean  keepRunning ;
     private   Font  paintFont ;
     private   volatile   String  timeMsg ;
     private   volatile   int  arcLen ;

     public   SecondCounter ()   {
        paintFont  =   new   Font ( "SansSerif" ,   Font . BOLD ,   14 );
        timeMsg  =   "never started" ;
        arcLen  =   0 ;
     }

     public   void  run ()   {
        runClock ();
     }

     public   void  runClock ()   {
         DecimalFormat  fmt  =   new   DecimalFormat ( "0.000" );
         long  normalSleepTime  =   100 ;
         long  nextSleepTime  =  normalSleepTime ;

         int  counter  =   0 ;
         long  startTime  =   System . currentTimeMillis ();
        keepRunning  =   true ;

         while   (  keepRunning  )   {
             try   {
                 Thread . sleep ( nextSleepTime );
             }   catch   (   InterruptedException  x  )   {
                 // ignore
             }

            counter ++ ;
             double  counterSecs  =  counter  /   10.0 ;
             double  elapsedSecs  =  
                 (   System . currentTimeMillis ()   -  startTime  )   /   1000.0 ;

             double  diffSecs  =  counterSecs  -  elapsedSecs ;

            nextSleepTime  =  normalSleepTime  +  
                     (   (   long   )   (  diffSecs  *   1000.0   )   );

             if   (  nextSleepTime  <   0   )   {
                nextSleepTime  =   0 ;
             }

            timeMsg  =  fmt . format ( counterSecs )   +   " - "   +  
                    fmt . format ( elapsedSecs )   +   " = "   +
                    fmt . format ( diffSecs );

            arcLen  =   (   (   (   int   )  counterSecs  )   %   60   )   *   360   /   60 ;
            repaint ();
         }
     }

     public   void  stopClock ()   {
        keepRunning  =   false ;
     }

     public   void  paint ( Graphics  g )   {
        g . setColor ( Color . black );
        g . setFont ( paintFont );
        g . drawString ( timeMsg ,   0 ,   15 );

        g . fillOval ( 0 ,   20 ,   100 ,   100 );    // black border

        g . setColor ( Color . white );
        g . fillOval ( 3 ,   23 ,   94 ,   94 );    // white for unused portion

        g . setColor ( Color . blue );    // blue for used portion
        g . fillArc ( 2 ,   22 ,   96 ,   96 ,   90 ,   - arcLen );
     }
}

source/chapter04/SecondCounterInaccurate.java

source/chapter04/SecondCounterInaccurate.java

import  java . awt . * ;
import  javax . swing . * ;
import  java . text . * ;

public   class   SecondCounterInaccurate   extends   JComponent   implements   Runnable   {
     private   volatile   boolean  keepRunning ;
     private   Font  paintFont ;
     private   volatile   String  timeMsg ;
     private   volatile   int  arcLen ;

     public   SecondCounterInaccurate ()   {
        paintFont  =   new   Font ( "SansSerif" ,   Font . BOLD ,   14 );
        timeMsg  =   "never started" ;
        arcLen  =   0 ;
     }

     public   void  run ()   {
        runClock ();
     }

     public   void  runClock ()   {
         DecimalFormat  fmt  =   new   DecimalFormat ( "0.000" );
         long  normalSleepTime  =   100 ;

         int  counter  =   0 ;
         long  startTime  =   System . currentTimeMillis ();
        keepRunning  =   true ;

         while   (  keepRunning  )   {
             try   {
                 Thread . sleep ( normalSleepTime );
             }   catch   (   InterruptedException  x  )   {
                 // ignore
             }

            counter ++ ;
             double  counterSecs  =  counter  /   10.0 ;
             double  elapsedSecs  =  
                 (   System . currentTimeMillis ()   -  startTime  )   /   1000.0 ;

             double  diffSecs  =  counterSecs  -  elapsedSecs ;

            timeMsg  =  fmt . format ( counterSecs )   +   " - "   +  
                    fmt . format ( elapsedSecs )   +   " = "   +
                    fmt . format ( diffSecs );

            arcLen  =   (   (   (   int   )  counterSecs  )   %   60   )   *   360   /   60 ;
            repaint ();
         }
     }

     public   void  stopClock ()   {
        keepRunning  =   false ;
     }

     public   void  paint ( Graphics  g )   {
        g . setColor ( Color . black );
        g . setFont ( paintFont );
        g . drawString ( timeMsg ,   0 ,   15 );

        g . fillOval ( 0 ,   20 ,   100 ,   100 );    // black border

        g . setColor ( Color . white );
        g . fillOval ( 3 ,   23 ,   94 ,   94 );    // white for unused portion

        g . setColor ( Color . blue );    // blue for used portion
        g . fillArc ( 2 ,   22 ,   96 ,   96 ,   90 ,   - arcLen );
     }
}

source/chapter04/SecondCounterInaccurateMain.java

source/chapter04/SecondCounterInaccurateMain.java

import  java . awt . * ;
import  java . awt . event . * ;
import  javax . swing . * ;
import  javax . swing . border . * ;

public   class   SecondCounterInaccurateMain   extends   JPanel   {
     private   SecondCounterInaccurate  sc ;
     private   JButton  startB ;
     private   JButton  stopB ;

     public   SecondCounterInaccurateMain ()   {
        sc  =   new   SecondCounterInaccurate ();
        startB  =   new   JButton ( "Start" );
        stopB  =   new   JButton ( "Stop" );

        stopB . setEnabled ( false );    // begin with this disabled

        startB . addActionListener ( new   ActionListener ()   {
                 public   void  actionPerformed ( ActionEvent  e )   {
                     // disable to stop more "start" requests
                    startB . setEnabled ( false );

                     // Create and start a new thread to run the counter
                     Thread  counterThread  =   new   Thread ( sc ,   "SecondCounter" );
                    counterThread . start ();

                    stopB . setEnabled ( true );
                    stopB . requestFocus ();
                 }
             });

        stopB . addActionListener ( new   ActionListener ()   {
                 public   void  actionPerformed ( ActionEvent  e )   {
                    stopB . setEnabled ( false );
                    sc . stopClock ();
                    startB . setEnabled ( true );
                    startB . requestFocus ();
                 }
             });

         JPanel  innerButtonP  =   new   JPanel ();
        innerButtonP . setLayout ( new   GridLayout ( 0 ,   1 ,   0 ,   3 ));
        innerButtonP . add ( startB );
        innerButtonP . add ( stopB );

         JPanel  buttonP  =   new   JPanel ();
        buttonP . setLayout ( new   BorderLayout ());
        buttonP . add ( innerButtonP ,   BorderLayout . NORTH );

         this . setLayout ( new   BorderLayout ( 10 ,   10 ));
         this . setBorder ( new   EmptyBorder ( 20 ,   20 ,   20 ,   20 ));
         this . add ( buttonP ,   BorderLayout . WEST );
         this . add ( sc ,   BorderLayout . CENTER );
     }

     public   static   void  main ( String []  args )   {
         SecondCounterInaccurateMain  scm  =   new   SecondCounterInaccurateMain ();

         JFrame  f  =   new   JFrame ( "Second Counter Inaccurate" );
        f . setContentPane ( scm );
        f . setSize ( 320 ,   200 );
        f . setVisible ( true );
        f . addWindowListener ( new   WindowAdapter ()   {
                 public   void  windowClosing ( WindowEvent  e )   {
                     System . exit ( 0 );
                 }
             });
     }
}

source/chapter04/SecondCounterLockup.java

source/chapter04/SecondCounterLockup.java

import  java . awt . * ;
import  javax . swing . * ;
import  java . text . * ;

public   class   SecondCounterLockup   extends   JComponent   {
     private   boolean  keepRunning ;
     private   Font  paintFont ;
     private   String  timeMsg ;
     private   int  arcLen ;

     public   SecondCounterLockup ()   {
        paintFont  =   new   Font ( "SansSerif" ,   Font . BOLD ,   14 );
        timeMsg  =   "never started" ;
        arcLen  =   0 ;
     }

     public   void  runClock ()   {
         System . out . println ( "thread running runClock() is "   +
                 Thread . currentThread (). getName ());

         DecimalFormat  fmt  =   new   DecimalFormat ( "0.000" );
         long  normalSleepTime  =   100 ;

         int  counter  =   0 ;
        keepRunning  =   true ;

         while   (  keepRunning  )   {
             try   {
                 Thread . sleep ( normalSleepTime );
             }   catch   (   InterruptedException  x  )   {
                 // ignore
             }

            counter ++ ;
             double  counterSecs  =  counter  /   10.0 ;

            timeMsg  =  fmt . format ( counterSecs );

            arcLen  =   (   (   (   int   )  counterSecs  )   %   60   )   *   360   /   60 ;
            repaint ();
         }
     }

     public   void  stopClock ()   {
        keepRunning  =   false ;
     }

     public   void  paint ( Graphics  g )   {
         System . out . println ( "thread that invoked paint() is "   +
                 Thread . currentThread (). getName ());

        g . setColor ( Color . black );
        g . setFont ( paintFont );
        g . drawString ( timeMsg ,   0 ,   15 );

        g . fillOval ( 0 ,   20 ,   100 ,   100 );    // black border

        g . setColor ( Color . white );
        g . fillOval ( 3 ,   23 ,   94 ,   94 );    // white for unused portion

        g . setColor ( Color . blue );    // blue for used portion
        g . fillArc ( 2 ,   22 ,   96 ,   96 ,   90 ,   - arcLen );
     }
}

source/chapter04/SecondCounterLockupMain.java

source/chapter04/SecondCounterLockupMain.java

import  java . awt . * ;
import  java . awt . event . * ;
import  javax . swing . * ;
import  javax . swing . border . * ;

public   class   SecondCounterLockupMain   extends   JPanel   {
     private   SecondCounterLockup  sc ;
     private   JButton  startB ;
     private   JButton  stopB ;

     public   SecondCounterLockupMain ()   {
        sc  =   new   SecondCounterLockup ();
        startB  =   new   JButton ( "Start" );
        stopB  =   new   JButton ( "Stop" );

        stopB . setEnabled ( false );    // begin with this disabled

        startB . addActionListener ( new   ActionListener ()   {
                 public   void  actionPerformed ( ActionEvent  e )   {
                     // disable to stop more "start" requests
                    startB . setEnabled ( false );

                     // Run the counter --watch out big trouble here!
                    sc . runClock ();

                    stopB . setEnabled ( true );
                    stopB . requestFocus ();
                 }
             });

        stopB . addActionListener ( new   ActionListener ()   {
                 public   void  actionPerformed ( ActionEvent  e )   {
                    stopB . setEnabled ( false );
                    sc . stopClock ();
                    startB . setEnabled ( true );
                    startB . requestFocus ();
                 }
             });

         JPanel  innerButtonP  =   new   JPanel ();
        innerButtonP . setLayout ( new   GridLayout ( 0 ,   1 ,   0 ,   3 ));
        innerButtonP . add ( startB );
        innerButtonP . add ( stopB );

         JPanel  buttonP  =   new   JPanel ();
        buttonP . setLayout ( new   BorderLayout ());
        buttonP . add ( innerButtonP ,   BorderLayout . NORTH );

         this . setLayout ( new   BorderLayout ( 10 ,   10 ));
         this . setBorder ( new   EmptyBorder ( 20 ,   20 ,   20 ,   20 ));
         this . add ( buttonP ,   BorderLayout . WEST );
         this . add ( sc ,   BorderLayout . CENTER );
     }

     public   static   void  main ( String []  args )   {
         SecondCounterLockupMain  scm  =   new   SecondCounterLockupMain ();

         JFrame  f  =   new   JFrame ( "Second Counter Lockup" );
        f . setContentPane ( scm );
        f . setSize ( 320 ,   200 );
        f . setVisible ( true );
        f . addWindowListener ( new   WindowAdapter ()   {
                 public   void  windowClosing ( WindowEvent  e )   {
                     System . exit ( 0 );
                 }
             });
     }
}

source/chapter04/SecondCounterMain.java

source/chapter04/SecondCounterMain.java

import  java . awt . * ;
import  java . awt . event . * ;
import  javax . swing . * ;
import  javax . swing . border . * ;

public   class   SecondCounterMain   extends   JPanel   {
     private   SecondCounter  sc ;
     private   JButton  startB ;
     private   JButton  stopB ;

     public   SecondCounterMain ()   {
        sc  =   new   SecondCounter ();
        startB  =   new   JButton ( "Start" );
        stopB  =   new   JButton ( "Stop" );

        stopB . setEnabled ( false );    // begin with this disabled

        startB . addActionListener ( new   ActionListener ()   {
                 public   void  actionPerformed ( ActionEvent  e )   {
                     // disable to stop more "start" requests
                    startB . setEnabled ( false );

                     // Create and start a new thread to run the counter
                     Thread  counterThread  =   new   Thread ( sc ,   "SecondCounter" );
                    counterThread . start ();

                    stopB . setEnabled ( true );
                    stopB . requestFocus ();
                 }
             });

        stopB . addActionListener ( new   ActionListener ()   {
                 public   void  actionPerformed ( ActionEvent  e )   {
                    stopB . setEnabled ( false );
                    sc . stopClock ();
                    startB . setEnabled ( true );
                    startB . requestFocus ();
                 }
             });

         JPanel  innerButtonP  =   new   JPanel ();
        innerButtonP . setLayout ( new   GridLayout ( 0 ,   1 ,   0 ,   3 ));
        innerButtonP . add ( startB );
        innerButtonP . add ( stopB );

         JPanel  buttonP  =   new   JPanel ();
        buttonP . setLayout ( new   BorderLayout ());
        buttonP . add ( innerButtonP ,   BorderLayout . NORTH );

         this . setLayout ( new   BorderLayout ( 10 ,   10 ));
         this . setBorder ( new   EmptyBorder ( 20 ,   20 ,   20 ,   20 ));
         this . add ( buttonP ,   BorderLayout . WEST );
         this . add ( sc ,   BorderLayout . CENTER );
     }

     public   static   void  main ( String []  args )   {
         SecondCounterMain  scm  =   new   SecondCounterMain ();

         JFrame  f  =   new   JFrame ( "Second Counter" );
        f . setContentPane ( scm );
        f . setSize ( 320 ,   200 );
        f . setVisible ( true );
        f . addWindowListener ( new   WindowAdapter ()   {
                 public   void  windowClosing ( WindowEvent  e )   {
                     System . exit ( 0 );
                 }
             });
     }
}

source/chapter04/SecondCounterRunnable.java

source/chapter04/SecondCounterRunnable.java

import  java . awt . * ;
import  javax . swing . * ;
import  java . text . * ;

public   class   SecondCounterRunnable   extends   JComponent   implements   Runnable   {
     private   volatile   boolean  keepRunning ;
     private   Font  paintFont ;
     private   volatile   String  timeMsg ;
     private   volatile   int  arcLen ;

     public   SecondCounterRunnable ()   {
        paintFont  =   new   Font ( "SansSerif" ,   Font . BOLD ,   14 );
        timeMsg  =   "never started" ;
        arcLen  =   0 ;
     }

     public   void  run ()   {
        runClock ();
     }

     public   void  runClock ()   {
         DecimalFormat  fmt  =   new   DecimalFormat ( "0.000" );
         long  normalSleepTime  =   100 ;

         int  counter  =   0 ;
        keepRunning  =   true ;

         while   (  keepRunning  )   {
             try   {
                 Thread . sleep ( normalSleepTime );
             }   catch   (   InterruptedException  x  )   {
                 // ignore
             }

            counter ++ ;
             double  counterSecs  =  counter  /   10.0 ;

            timeMsg  =  fmt . format ( counterSecs );

            arcLen  =   (   (   (   int   )  counterSecs  )   %   60   )   *   360   /   60 ;
            repaint ();
         }
     }

     public   void  stopClock ()   {
        keepRunning  =   false ;
     }

     public   void  paint ( Graphics  g )   {
        g . setColor ( Color . black );
        g . setFont ( paintFont );
        g . drawString ( timeMsg ,   0 ,   15 );

        g . fillOval ( 0 ,   20 ,   100 ,   100 );    // black border

        g . setColor ( Color . white );
        g . fillOval ( 3 ,   23 ,   94 ,   94 );    // white for unused portion

        g . setColor ( Color . blue );    // blue for used portion
        g . fillArc ( 2 ,   22 ,   96 ,   96 ,   90 ,   - arcLen );
     }
}

source/chapter04/SecondCounterRunnableMain.java

source/chapter04/SecondCounterRunnableMain.java

import  java . awt . * ;
import  java . awt . event . * ;
import  javax . swing . * ;
import  javax . swing . border . * ;

public   class   SecondCounterRunnableMain   extends   JPanel   {
     private   SecondCounterRunnable  sc ;
     private   JButton  startB ;
     private   JButton  stopB ;

     public   SecondCounterRunnableMain ()   {
        sc  =   new   SecondCounterRunnable ();
        startB  =   new   JButton ( "Start" );
        stopB  =   new   JButton ( "Stop" );

        stopB . setEnabled ( false );    // begin with this disabled

        startB . addActionListener ( new   ActionListener ()   {
                 public   void  actionPerformed ( ActionEvent  e )   {
                     // disable to stop more "start" requests
                    startB . setEnabled ( false );

                     // Create and start a new thread to run the counter
                     Thread  counterThread  =   new   Thread ( sc ,   "SecondCounter" );
                    counterThread . start ();

                    stopB . setEnabled ( true );
                    stopB . requestFocus ();
                 }
             });

        stopB . addActionListener ( new   ActionListener ()   {
                 public   void  actionPerformed ( ActionEvent  e )   {
                    stopB . setEnabled ( false );
                    sc . stopClock ();
                    startB . setEnabled ( true );
                    startB . requestFocus ();
                 }
             });

         JPanel  innerButtonP  =   new   JPanel ();
        innerButtonP . setLayout ( new   GridLayout ( 0 ,   1 ,   0 ,   3 ));
        innerButtonP . add ( startB );
        innerButtonP . add ( stopB );

         JPanel  buttonP  =   new   JPanel ();
        buttonP . setLayout ( new   BorderLayout ());
        buttonP . add ( innerButtonP ,   BorderLayout . NORTH );

         this . setLayout ( new   BorderLayout ( 10 ,   10 ));
         this . setBorder ( new   EmptyBorder ( 20 ,   20 ,   20 ,   20 ));
         this . add ( buttonP ,   BorderLayout . WEST );
         this . add ( sc ,   BorderLayout . CENTER );
     }

     public   static   void  main ( String []  args )   {
         SecondCounterRunnableMain  scm  =   new   SecondCounterRunnableMain ();

         JFrame  f  =   new   JFrame ( "Second Counter Runnable" );
        f . setContentPane ( scm );
        f . setSize ( 320 ,   200 );
        f . setVisible ( true );
        f . addWindowListener ( new   WindowAdapter ()   {
                 public   void  windowClosing ( WindowEvent  e )   {
                     System . exit ( 0 );
                 }
             });
     }
}

source/chapter05/AlternateStop.java

source/chapter05/AlternateStop.java

public   class   AlternateStop   extends   Object   implements   Runnable   {
     private   volatile   boolean  stopRequested ;
     private   Thread  runThread ;

     public   void  run ()   {
        runThread  =   Thread . currentThread ();
        stopRequested  =   false ;

         int  count  =   0 ;

         while   (   ! stopRequested  )   {
             System . out . println ( "Running ... count="   +  count );
            count ++ ;

             try   {
                 Thread . sleep ( 300 );
             }   catch   (   InterruptedException  x  )   {
                 Thread . currentThread (). interrupt ();   // re-assert interrupt
             }
         }
     }

     public   void  stopRequest ()   {
        stopRequested  =   true ;

         if   (  runThread  !=   null   )   {
            runThread . interrupt ();
         }
     }

     public   static   void  main ( String []  args )   {
         AlternateStop  as  =   new   AlternateStop ();
         Thread  t  =   new   Thread ( as );
        t . start ();

         try   {
             Thread . sleep ( 2000 );
         }   catch   (   InterruptedException  x  )   {
             // ignore
         }

        as . stopRequest ();
     }
}

source/chapter05/AlternateSuspendResume.java

source/chapter05/AlternateSuspendResume.java

public   class   AlternateSuspendResume  
         extends   Object  
         implements   Runnable   {

     private   volatile   int  firstVal ;
     private   volatile   int  secondVal ;
     private   volatile   boolean  suspended ;

     public   boolean  areValuesEqual ()   {
         return   (  firstVal  ==  secondVal  );
     }

     public   void  run ()   {
         try   {
            suspended  =   false ;
            firstVal  =   0 ;
            secondVal  =   0 ;
            workMethod ();
         }   catch   (   InterruptedException  x  )   {
             System . out . println (
                 "interrupted while in workMethod()" );
         }
     }

     private   void  workMethod ()   throws   InterruptedException   {
         int  val  =   1 ;

         while   (   true   )   {
             // blocks only if suspended is true
            waitWhileSuspended ();  

            stepOne ( val );
            stepTwo ( val );
            val ++ ;

             // blocks only if suspended is true
            waitWhileSuspended ();  

             Thread . sleep ( 200 );    // pause before looping again
         }
     }

     private   void  stepOne ( int  newVal )  
                     throws   InterruptedException   {

        firstVal  =  newVal ;

         // simulate some other lengthy process
         Thread . sleep ( 300 );   
     }

     private   void  stepTwo ( int  newVal )   {
        secondVal  =  newVal ;
     }

     public   void  suspendRequest ()   {
        suspended  =   true ;
     }

     public   void  resumeRequest ()   {
        suspended  =   false ;
     }

     private   void  waitWhileSuspended ()  
                 throws   InterruptedException   {

         // This is an example of a "busy wait" technique.  It is
         // not the best way to wait for a condition to change 
         // because it continually requires some processor 
         // cycles to perform the checks.  A better technique 
         // is to use Java's built-in wait-notify mechanism.
         while   (  suspended  )   {
             Thread . sleep ( 200 );
         }
     }

     public   static   void  main ( String []  args )   {
         AlternateSuspendResume  asr  =  
                 new   AlternateSuspendResume ();

         Thread  t  =   new   Thread ( asr );
        t . start ();

         // let the other thread get going and run for a while
         try   {   Thread . sleep ( 1000 );   }  
         catch   (   InterruptedException  x  )   {   }

         for   (   int  i  =   0 ;  i  <   10 ;  i ++   )   {
            asr . suspendRequest ();

             // Give the thread a chance to notice the 
             // suspension request.
             try   {   Thread . sleep ( 350 );   }  
             catch   (   InterruptedException  x  )   {   }

             System . out . println ( "dsr.areValuesEqual()="   +  
                    asr . areValuesEqual ());

            asr . resumeRequest ();

             try   {  
                 // Pause for a random amount of time 
                 // between 0 and 2 seconds.
                 Thread . sleep (
                         (   long   )   ( Math . random ()   *   2000.0 )   );
             }   catch   (   InterruptedException  x  )   {
                 // ignore
             }
         }

         System . exit ( 0 );   // abruptly terminate application
     }
}

source/chapter05/BestReplacement.java

source/chapter05/BestReplacement.java

// uses BooleanLock from chapter 17

public   class   BestReplacement   extends   Object   {
     private   Thread  internalThread ;
     private   volatile   boolean  stopRequested ;

     private   BooleanLock  suspendRequested ;
     private   BooleanLock  internalThreadSuspended ;

     public   BestReplacement ()   {
        stopRequested  =   false ;

        suspendRequested  =   new   BooleanLock ( false );
        internalThreadSuspended  =   new   BooleanLock ( false );

         Runnable  r  =   new   Runnable ()   {
                 public   void  run ()   {
                     try   {
                        runWork ();
                     }   catch   (   Exception  x  )   {
                         // in case ANY exception slips through
                        x . printStackTrace ();  
                     }
                 }
             };

        internalThread  =   new   Thread ( r );
        internalThread . start ();
     }

     private   void  runWork ()   {
         int  count  =   0 ;

         while   (   ! stopRequested  )   {
             try   {
                waitWhileSuspended ();
             }   catch   (   InterruptedException  x  )   {
                 // Reassert interrupt so that remaining code
                 // sees that an interrupt has been requested.
                 Thread . currentThread (). interrupt ();  

                 // Reevaluate while condition --probably 
                 // false now.
                 continue ;
             }

             System . out . println ( "Part I - count="   +  count );

             try   {
                 Thread . sleep ( 1000 );
             }   catch   (   InterruptedException  x  )   {
                 Thread . currentThread (). interrupt ();   // reassert
                 // continue on as if sleep completed normally
             }

             System . out . println ( "Part II - count="   +  count );

             try   {
                 Thread . sleep ( 1000 );
             }   catch   (   InterruptedException  x  )   {
                 Thread . currentThread (). interrupt ();   // reassert
                 // continue on as if sleep completed normally
             }

             System . out . println ( "Part III - count="   +  count );

            count ++ ;
         }
     }

     private   void  waitWhileSuspended ()  
                     throws   InterruptedException   {

         // only called by the internal thread - private method

         synchronized   (  suspendRequested  )   {
             if   (  suspendRequested . isTrue ()   )   {
                 try   {
                    internalThreadSuspended . setValue ( true );
                    suspendRequested . waitUntilFalse ( 0 );  
                 }   finally   {
                    internalThreadSuspended . setValue ( false );
                 }
             }
         }
     }

     public   void  suspendRequest ()   {
        suspendRequested . setValue ( true );
     }

     public   void  resumeRequest ()   {
        suspendRequested . setValue ( false );
     }

     public   boolean  waitForActualSuspension ( long  msTimeout )  
                     throws   InterruptedException   {

         // Returns 'true' if suspended, 'false' if the 
         // timeout expired.

         return  internalThreadSuspended . waitUntilTrue ( msTimeout );
     }

     public   void  stopRequest ()   {
        stopRequested  =   true ;
        internalThread . interrupt ();
     }

     public   boolean  isAlive ()   {
         return  internalThread . isAlive ();
     }

     public   static   void  main ( String []  args )   {
         try   {
             BestReplacement  br  =   new   BestReplacement ();
             System . out . println (
                     "--> just created, br.isAlive()="   +  
                    br . isAlive ());
             Thread . sleep ( 4200 );

             long  startTime  =   System . currentTimeMillis ();
            br . suspendRequest ();
             System . out . println (
                     "--> just submitted a suspendRequest" );

             boolean  suspensionTookEffect  =  
                    br . waitForActualSuspension ( 10000 );
             long  stopTime  =   System . currentTimeMillis ();

             if   (  suspensionTookEffect  )   {
                 System . out . println (
                     "--> the internal thread took "   +
                     ( stopTime  -  startTime )   +   " ms to notice "   +
                     "\n    the suspend request and is now "   +
                     "suspended." );
             }   else   {
                 System . out . println (
                     "--> the internal thread did not notice "   +
                     "the suspend request "   +
                     "\n    within 10 seconds." );
             }

             Thread . sleep ( 5000 );

            br . resumeRequest ();
             System . out . println (
                     "--> just submitted a resumeRequest" );
             Thread . sleep ( 2200 );

            br . stopRequest ();
             System . out . println (
                     "--> just submitted a stopRequest" );
         }   catch   (   InterruptedException  x  )   {
             // ignore
         }
     }
}

source/chapter05/BooleanLock.java

source/chapter05/BooleanLock.java

public   class   BooleanLock   extends   Object   {
     private   boolean  value ;

     public   BooleanLock ( boolean  initialValue )   {
        value  =  initialValue ;
     }

     public   BooleanLock ()   {
         this ( false );
     }

     public   synchronized   void  setValue ( boolean  newValue )   {
         if   (  newValue  !=  value  )   {
            value  =  newValue ;
            notifyAll ();
         }
     }

     public   synchronized   boolean  waitToSetTrue ( long  msTimeout )  
             throws   InterruptedException   {

         boolean  success  =  waitUntilFalse ( msTimeout );
         if   (  success  )   {
            setValue ( true );
         }

         return  success ;
     }

     public   synchronized   boolean  waitToSetFalse ( long  msTimeout )  
             throws   InterruptedException   {

         boolean  success  =  waitUntilTrue ( msTimeout );
         if   (  success  )   {
            setValue ( false );
         }

         return  success ;
     }

     public   synchronized   boolean  isTrue ()   {
         return  value ;
     }

     public   synchronized   boolean  isFalse ()   {
         return   ! value ;
     }

     public   synchronized   boolean  waitUntilTrue ( long  msTimeout )  
             throws   InterruptedException   {

         return  waitUntilStateIs ( true ,  msTimeout );
     }

     public   synchronized   boolean  waitUntilFalse ( long  msTimeout )  
             throws   InterruptedException   {

         return  waitUntilStateIs ( false ,  msTimeout );
     }

     public   synchronized   boolean  waitUntilStateIs (
                 boolean  state ,  
                 long  msTimeout
             )   throws   InterruptedException   {

         if   (  msTimeout  ==   0L   )   {
             while   (  value  !=  state  )   {
                wait ();    // wait indefinitely until notified
             }

             // condition has finally been met
             return   true ;
         }  

         // only wait for the specified amount of time
         long  endTime  =   System . currentTimeMillis ()   +  msTimeout ;
         long  msRemaining  =  msTimeout ;

         while   (   (  value  !=  state  )   &&   (  msRemaining  >   0L   )   )   {
            wait ( msRemaining );
            msRemaining  =  endTime  -   System . currentTimeMillis ();
         }

         // May have timed out, or may have met value, 
         // calculate return value.
         return   (  value  ==  state  );
     }
}

source/chapter05/DaemonThread.java

source/chapter05/DaemonThread.java

public   class   DaemonThread   extends   Object   implements   Runnable   {
     public   void  run ()   {
         System . out . println ( "entering run()" );

         try   {
             System . out . println ( "in run() - currentThread()="   +  
                     Thread . currentThread ());

             while   (   true   )   {
                 try   {   Thread . sleep ( 500 );   }  
                 catch   (   InterruptedException  x  )   {}

                 System . out . println ( "in run() - woke up again" );
             }
         }   finally   {
             System . out . println ( "leaving run()" );
         }
     }
}

source/chapter05/DaemonThreadMain.java

source/chapter05/DaemonThreadMain.java

public   class   DaemonThreadMain   extends   Object   {
     public   static   void  main ( String []  args )   {
         System . out . println ( "entering main()" );

         Thread  t  =   new   Thread ( new   DaemonThread ());
        t . setDaemon ( true );
        t . start ();

         try   {   Thread . sleep ( 3000 );   }   catch   (   InterruptedException  x  )   {   }

         System . out . println ( "leaving main()" );
     }
}

source/chapter05/DeprecatedStop.java

source/chapter05/DeprecatedStop.java

public   class   DeprecatedStop   extends   Object   implements   Runnable   {

     public   void  run ()   {
         int  count  =   0 ;

         while   (   true   )   {
             System . out . println ( "Running ... count="   +  count );
            count ++ ;

             try   {
                 Thread . sleep ( 300 );
             }   catch   (   InterruptedException  x  )   {
                 // ignore
             }
         }
     }


     public   static   void  main ( String []  args )   {
         DeprecatedStop  ds  =   new   DeprecatedStop ();
         Thread  t  =   new   Thread ( ds );
        t . start ();

         try   {
             Thread . sleep ( 2000 );
         }   catch   (   InterruptedException  x  )   {
             // ignore
         }

         // Abruptly stop the other thread in its tracks!
        t . stop ();
     }
}

source/chapter05/DeprecatedSuspendResume.java

source/chapter05/DeprecatedSuspendResume.java

public   class   DeprecatedSuspendResume  
         extends   Object  
         implements   Runnable   {

     private   volatile   int  firstVal ;
     private   volatile   int  secondVal ;

     public   boolean  areValuesEqual ()   {
         return   (  firstVal  ==  secondVal  );
     }

     public   void  run ()   {
         try   {
            firstVal  =   0 ;
            secondVal  =   0 ;
            workMethod ();
         }   catch   (   InterruptedException  x  )   {
             System . out . println (
                     "interrupted while in workMethod()" );
         }
     }

     private   void  workMethod ()   throws   InterruptedException   {
         int  val  =   1 ;

         while   (   true   )   {
            stepOne ( val );
            stepTwo ( val );
            val ++ ;

             Thread . sleep ( 200 );    // pause before looping again
         }
     }

     private   void  stepOne ( int  newVal )  
             throws   InterruptedException   {

        firstVal  =  newVal ;
         Thread . sleep ( 300 );    // simulate some other long process
     }

     private   void  stepTwo ( int  newVal )   {
        secondVal  =  newVal ;
     }

     public   static   void  main ( String []  args )   {
         DeprecatedSuspendResume  dsr  =  
                 new   DeprecatedSuspendResume ();
         Thread  t  =   new   Thread ( dsr );
        t . start ();

         // let the other thread get going and run for a while
         try   {   Thread . sleep ( 1000 );   }  
         catch   (   InterruptedException  x  )   {   }

         for   (   int  i  =   0 ;  i  <   10 ;  i ++   )   {
            t . suspend ();
             System . out . println ( "dsr.areValuesEqual()="   +  
                                dsr . areValuesEqual ());
            t . resume ();
             try   {  
                 // Pause for a random amount of time 
                 // between 0 and 2 seconds.
                 Thread . sleep (  
                         (   long   )   ( Math . random ()   *   2000.0 )   );
             }   catch   (   InterruptedException  x  )   {
                 // ignore
             }
         }

         System . exit ( 0 );   // abruptly terminate application
     }
}

source/chapter05/GeneralInterrupt.java

source/chapter05/GeneralInterrupt.java

public   class   GeneralInterrupt   extends   Object   implements   Runnable   {
     public   void  run ()   {
         /*
        try {
            System.out.println("in run() - about to sleep for 20 seconds");
            work();
            System.out.println("in run() - woke up");
        } catch ( InterruptedException x ) {
            System.out.println("in run() - interrupted while sleeping");
            //return;
        }
        */

         try   {
             System . out . println ( "in run() - about to work2()" );
            work2 ();
             System . out . println ( "in run() - back from  work2()" );
         }   catch   (   InterruptedException  x  )   {
             System . out . println ( "in run() - interrupted in work2()" );
             return ;
         }

         System . out . println ( "in run() - doing stuff after nap" );
         System . out . println ( "in run() - leaving normally" );
     }

     public   void  work2 ()   throws   InterruptedException   {
         while   (   true   )   {
             if   (   Thread . currentThread (). isInterrupted ()   )   {
                 System . out . println ( "C isInterrupted()="   +  
                     Thread . currentThread (). isInterrupted ());
                 Thread . sleep ( 2000 );
                 System . out . println ( "D isInterrupted()="   +  
                     Thread . currentThread (). isInterrupted ());
             }
         }
     }

     public   void  work ()   throws   InterruptedException   {
         while   (   true   )   {
             for   (   int  i  =   0 ;  i  <   100000 ;  i ++   )   {
                 int  j  =  i  *   2 ;
             }

             System . out . println ( "A isInterrupted()="   +  
                 Thread . currentThread (). isInterrupted ());

             if   (   Thread . interrupted ()   )   {
                 System . out . println ( "B isInterrupted()="   +  
                     Thread . currentThread (). isInterrupted ());
                 throw   new   InterruptedException ();
             }
         }
     }


     public   static   void  main ( String []  args )   {
         GeneralInterrupt  si  =   new   GeneralInterrupt ();
         Thread  t  =   new   Thread ( si );
        t . start ();

         // be sure that the new thread gets a chance to run for a while
         try   {   Thread . sleep ( 2000 );   }   catch   (   InterruptedException  x  )   {   }

         System . out . println ( "in main() - interrupting other thread" );
        t . interrupt ();
         System . out . println ( "in main() - leaving" );
     }
}

source/chapter05/InterruptCheck.java

source/chapter05/InterruptCheck.java

public   class   InterruptCheck   extends   Object   {
     public   static   void  main ( String []  args )   {
         Thread  t  =   Thread . currentThread ();
         System . out . println ( "Point A: t.isInterrupted()="   +  t . isInterrupted ());
        t . interrupt ();
         System . out . println ( "Point B: t.isInterrupted()="   +  t . isInterrupted ());
         System . out . println ( "Point C: t.isInterrupted()="   +  t . isInterrupted ());

         try   {
             Thread . sleep ( 2000 );
             System . out . println ( "was NOT interrupted" );
         }   catch   (   InterruptedException  x  )   {
             System . out . println ( "was interrupted" );
         }

         System . out . println ( "Point D: t.isInterrupted()="   +  t . isInterrupted ());
     }
}

source/chapter05/InterruptReset.java

source/chapter05/InterruptReset.java

public   class   InterruptReset   extends   Object   {
     public   static   void  main ( String []  args )   {
         System . out . println (
             "Point X: Thread.interrupted()="   +   Thread . interrupted ());
         Thread . currentThread (). interrupt ();
         System . out . println (
             "Point Y: Thread.interrupted()="   +   Thread . interrupted ());
         System . out . println (
             "Point Z: Thread.interrupted()="   +   Thread . interrupted ());
     }
}

source/chapter05/PendingInterrupt.java

source/chapter05/PendingInterrupt.java

public   class   PendingInterrupt   extends   Object   {
     public   static   void  main ( String []  args )   {
         if   (  args . length  >   0   )   {
             Thread . currentThread (). interrupt ();
         }  

         long  startTime  =   System . currentTimeMillis ();
         try   {
             Thread . sleep ( 2000 );
             System . out . println ( "was NOT interrupted" );
         }   catch   (   InterruptedException  x  )   {
             System . out . println ( "was interrupted" );
         }

         System . out . println (
                 "elapsedTime="   +   (   System . currentTimeMillis ()   -  startTime  ));
     }
}

source/chapter05/PiInterrupt.java

source/chapter05/PiInterrupt.java

public   class   PiInterrupt   extends   Object   implements   Runnable   {
     private   double  latestPiEstimate ;

     public   void  run ()   {
         try   {
             System . out . println ( "for comparison, Math.PI="   +  
                                 Math . PI );
            calcPi ( 0.000000001 );
             System . out . println ( "within accuracy, latest pi="   +  
                                latestPiEstimate );
         }   catch   (   InterruptedException  x  )   {
             System . out . println ( "INTERRUPTED!! latest pi="   +  
                                latestPiEstimate );
         }
     }

     private   void  calcPi ( double  accuracy )  
                 throws   InterruptedException   {

        latestPiEstimate  =   0.0 ;
         long  iteration  =   0 ;
         int  sign  =   - 1 ;

         while   (   Math . abs ( latestPiEstimate  -   Math . PI )   >  
                accuracy  )   {

             if   (   Thread . interrupted ()   )   {
                 throw   new   InterruptedException ();
             }

            iteration ++ ;
            sign  =   - sign ;
            latestPiEstimate  +=  
                    sign  *   4.0   /   (   (   2   *  iteration  )   -   1   );
         }
     }

     public   static   void  main ( String []  args )   {
         PiInterrupt  pi  =   new   PiInterrupt ();
         Thread  t  =   new   Thread ( pi );
        t . start ();

         try   {
             Thread . sleep ( 10000 );
            t . interrupt ();
         }   catch   (   InterruptedException  x  )   {
             // ignore
         }
     }
}

source/chapter05/SleepInterrupt.java

source/chapter05/SleepInterrupt.java

public   class   SleepInterrupt   extends   Object   implements   Runnable   {
     public   void  run ()   {
         try   {
             System . out . println (
                     "in run() - about to sleep for 20 seconds" );
             Thread . sleep ( 20000 );
             System . out . println ( "in run() - woke up" );
         }   catch   (   InterruptedException  x  )   {
             System . out . println (
                     "in run() - interrupted while sleeping" );
             return ;
         }

         System . out . println ( "in run() - doing stuff after nap" );
         System . out . println ( "in run() - leaving normally" );
     }


     public   static   void  main ( String []  args )   {
         SleepInterrupt  si  =   new   SleepInterrupt ();
         Thread  t  =   new   Thread ( si );
        t . start ();

         // Be sure that the new thread gets a chance to 
         // run for a while.
         try   {   Thread . sleep ( 2000 );   }  
         catch   (   InterruptedException  x  )   {   }

         System . out . println (
                 "in main() - interrupting other thread" );
        t . interrupt ();
         System . out . println ( "in main() - leaving" );
     }
}

source/chapter05/VisualSuspendResume.java

source/chapter05/VisualSuspendResume.java

import  java . awt . * ;
import  java . awt . event . * ;
import  javax . swing . * ;

public   class   VisualSuspendResume  
             extends   JPanel  
             implements   Runnable   {

     private   static   final   String []  symbolList  =  
             {   "|" ,   "/" ,   "-" ,   "\\" ,   "|" ,   "/" ,   "-" ,   "\\"   };

     private   Thread  runThread ;
     private   JTextField  symbolTF ;

     public   VisualSuspendResume ()   {
        symbolTF  =   new   JTextField ();  
        symbolTF . setEditable ( false );
        symbolTF . setFont ( new   Font ( "Monospaced" ,   Font . BOLD ,   26 ));
        symbolTF . setHorizontalAlignment ( JTextField . CENTER );

         final   JButton  suspendB  =   new   JButton ( "Suspend" );
         final   JButton  resumeB  =   new   JButton ( "Resume" );

        suspendB . addActionListener ( new   ActionListener ()   {
                 public   void  actionPerformed ( ActionEvent  e )   {
                    suspendNow ();
                 }
             });

        resumeB . addActionListener ( new   ActionListener ()   {
                 public   void  actionPerformed ( ActionEvent  e )   {
                    resumeNow ();
                 }
             });
        
         JPanel  innerStackP  =   new   JPanel ();
        innerStackP . setLayout ( new   GridLayout ( 0 ,   1 ,   3 ,   3 ));
        innerStackP . add ( symbolTF );
        innerStackP . add ( suspendB );
        innerStackP . add ( resumeB );

         this . setLayout ( new   FlowLayout ( FlowLayout . CENTER ));
         this . add ( innerStackP );
     }

     private   void  suspendNow ()   {
         if   (  runThread  !=   null   )   {   // avoid NullPointerException
            runThread . suspend ();
         }
     }

     private   void  resumeNow ()   {
         if   (  runThread  !=   null   )   {   // avoid NullPointerException
            runThread . resume ();
         }
     }

     public   void  run ()   {
         try   {
             // Store this for the suspendNow() and 
             // resumeNow() methods to use.
            runThread  =   Thread . currentThread ();
             int  count  =   0 ;

             while   (   true   )   {
                 // each time through, show the next symbol
                symbolTF . setText (
                    symbolList [  count  %  symbolList . length  ]);
                 Thread . sleep ( 200 );
                count ++ ;
             }
         }   catch   (   InterruptedException  x  )   {
             // ignore
         }   finally   {
             // The thread is about to die, make sure that the 
             // reference to it is also lost.
            runThread  =   null ;
         }
     }

     public   static   void  main ( String []  args )   {
         VisualSuspendResume  vsr  =   new   VisualSuspendResume ();
         Thread  t  =   new   Thread ( vsr );
        t . start ();

         JFrame  f  =   new   JFrame ( "Visual Suspend Resume" );
        f . setContentPane ( vsr );
        f . setSize ( 320 ,   200 );
        f . setVisible ( true );
        f . addWindowListener ( new   WindowAdapter ()   {
                 public   void  windowClosing ( WindowEvent  e )   {
                     System . exit ( 0 );
                 }
             });
     }
}

source/chapter06/GetPriority.java

source/chapter06/GetPriority.java

public   class   GetPriority   extends   Object   {
     private   static   Runnable  makeRunnable ()   {
         Runnable  r  =    new   Runnable ()   {
                 public   void  run ()   {
                     for   (   int  i  =   0 ;  i  <   5 ;  i ++   )   {
                         Thread  t  =   Thread . currentThread ();
                         System . out . println (
                             "in run() - priority="   +  
                            t . getPriority ()   +
                             ", name="   +  t . getName ());

                         try   {
                             Thread . sleep ( 2000 );
                         }   catch   (   InterruptedException  x  )   {
                             // ignore
                         }
                     }
                 }
             };

         return  r ;
     }

     public   static   void  main ( String []  args )   {
         System . out . println (
             "in main() - Thread.currentThread().getPriority()="   +
             Thread . currentThread (). getPriority ());

         System . out . println (
             "in main() - Thread.currentThread().getName()="   +
             Thread . currentThread (). getName ());

         Thread  threadA  =   new   Thread ( makeRunnable (),   "threadA" );
        threadA . start ();

         try   {   Thread . sleep ( 3000 );   }  
         catch   (   InterruptedException  x  )   {   }

         System . out . println ( "in main() - threadA.getPriority()="   +
                threadA . getPriority ());
     }
}

source/chapter06/PriorityCompete.java

source/chapter06/PriorityCompete.java

public   class   PriorityCompete   extends   Object   {
     private   volatile   int  count ;
     private   boolean  yield ;
     private   Thread  internalThread ;
     private   volatile   boolean  noStopRequested ;

     public   PriorityCompete (
                 String  name ,  
                 int  priority ,  
                 boolean  yield
             )   {

        count  =   0 ;
         this . yield  =  yield ;

        noStopRequested  =   true ;
         Runnable  r  =   new   Runnable ()   {
                 public   void  run ()   {
                     try   {
                        runWork ();
                     }   catch   (   Exception  x  )   {
                         // in case ANY exception slips through
                        x . printStackTrace ();  
                     }
                 }
             };

        internalThread  =   new   Thread ( r ,  name );
        internalThread . setPriority ( priority );
     }

     private   void  runWork ()   {
         Thread . yield ();

         while   (  noStopRequested  )   {
             if   (  yield  )   {
                 Thread . yield ();
             }

            count ++ ;

             for   (   int  i  =   0 ;  i  <   1000 ;  i ++   )   {
                 double  x  =  i  *   Math . PI  /   Math . E ;
             }
         }
     }

     public   void  startRequest ()   {
        internalThread . start ();
     }

     public   void  stopRequest ()   {
        noStopRequested  =   false ;
     }

     public   int  getCount ()   {
         return  count ;
     }

     public   String  getNameAndPriority ()   {
         return  internalThread . getName ()   +  
             ": priority="   +  internalThread . getPriority ();
     }

     private   static   void  runSet ( boolean  yield )   {
         PriorityCompete []  pc  =   new   PriorityCompete [ 3 ];
        pc [ 0 ]   =   new   PriorityCompete ( "PC0" ,   3 ,  yield );
        pc [ 1 ]   =   new   PriorityCompete ( "PC1" ,   6 ,  yield );
        pc [ 2 ]   =   new   PriorityCompete ( "PC2" ,   6 ,  yield );

         // let the dust settle for a bit before starting them up
         try   {   Thread . sleep ( 1000 );   }  
         catch   (   InterruptedException  x  )   {   }

         for   (   int  i  =   0 ;  i  <  pc . length ;  i ++   )   {
            pc [ i ]. startRequest ();
         }

         long  startTime  =   System . currentTimeMillis ();
         try   {   Thread . sleep ( 10000 );   }  
         catch   (   InterruptedException  x  )   {   }

         for   (   int  i  =   0 ;  i  <  pc . length ;  i ++   )   {
            pc [ i ]. stopRequest ();
         }

         long  stopTime  =   System . currentTimeMillis ();

         // let things settle down again
         try   {   Thread . sleep ( 1000 );   }  
         catch   (   InterruptedException  x  )   {   }

         int  totalCount  =   0 ;
         for   (   int  i  =   0 ;  i  <  pc . length ;  i ++   )   {
            totalCount  +=  pc [ i ]. getCount ();
         }

         System . out . println ( "totalCount="   +  totalCount  +
             ", count/ms="   +  roundTo ((( double )  totalCount )   /  
                                     ( stopTime  -  startTime ),   3 ));

         for   (   int  i  =   0 ;  i  <  pc . length ;  i ++   )   {
             double  perc  =  roundTo ( 100.0   *  pc [ i ]. getCount ()   /  
                                    totalCount ,   2 );
             System . out . println ( pc [ i ]. getNameAndPriority ()   +  
                 ", "   +  perc  +   "%, count="   +  pc [ i ]. getCount ());
         }
     }

     public   static   double  roundTo ( double  val ,   int  places )   {
         double  factor  =   Math . pow ( 10 ,  places );
         return   (   ( int )   (   (  val  *  factor  )   +   0.5   )   )   /  factor ;
     }

     public   static   void  main ( String []  args )   {
         Runnable  r  =   new   Runnable ()   {
                 public   void  run ()   {
                     System . out . println (
                             "Run without using yield()" );
                     System . out . println (
                             "=========================" );
                    runSet ( false );

                     System . out . println ();
                     System . out . println ( "Run using yield()" );
                     System . out . println ( "=================" );
                    runSet ( true );
                 }
             };

         Thread  t  =   new   Thread ( r ,   "PriorityCompete" );
        t . setPriority ( Thread . MAX_PRIORITY  -   1 );
        t . start ();
     }
}

source/chapter06/SetPriority.java

source/chapter06/SetPriority.java

public   class   SetPriority   extends   Object   {
     private   static   Runnable  makeRunnable ()   {
         Runnable  r  =    new   Runnable ()   {
                 public   void  run ()   {
                     for   (   int  i  =   0 ;  i  <   5 ;  i ++   )   {
                         Thread  t  =   Thread . currentThread ();
                         System . out . println (
                             "in run() - priority="   +  
                            t . getPriority ()   +
                             ", name="   +  t . getName ());

                         try   {
                             Thread . sleep ( 2000 );
                         }   catch   (   InterruptedException  x  )   {
                             // ignore
                         }
                     }
                 }
             };

         return  r ;
     }

     public   static   void  main ( String []  args )   {
         Thread  threadA  =   new   Thread ( makeRunnable (),   "threadA" );
        threadA . setPriority ( 8 );
        threadA . start ();

         Thread  threadB  =   new   Thread ( makeRunnable (),   "threadB" );
        threadB . setPriority ( 2 );
        threadB . start ();

         Runnable  r  =   new   Runnable ()   {
                 public   void  run ()   {
                     Thread  threadC  =  
                         new   Thread ( makeRunnable (),   "threadC" );
                    threadC . start ();
                 }
             };
         Thread  threadD  =   new   Thread ( r ,   "threadD" );
        threadD . setPriority ( 7 );
        threadD . start ();

         try   {   Thread . sleep ( 3000 );   }  
         catch   (   InterruptedException  x  )   {   }

        threadA . setPriority ( 3 );
         System . out . println ( "in main() - threadA.getPriority()="   +
                threadA . getPriority ());
     }
}

source/chapter07/BothInMethod.java

source/chapter07/BothInMethod.java

public   class   BothInMethod   extends   Object   {
     private   String  objID ;

     public   BothInMethod ( String  objID )   {
         this . objID  =  objID ;
     }

     public   void  doStuff ( int  val )   {
        print ( "entering doStuff()" );
         int  num  =  val  *   2   +  objID . length ();
        print ( "in doStuff() - local variable num="   +  num );

         // slow things down to make observations
         try   {   Thread . sleep ( 2000 );   }   catch   (   InterruptedException  x  )   {   }

        print ( "leaving doStuff()" );
     }

     public   void  print ( String  msg )   {
        threadPrint ( "objID="   +  objID  +   " - "   +  msg );
     }

     public   static   void  threadPrint ( String  msg )   {
         String  threadName  =   Thread . currentThread (). getName ();
         System . out . println ( threadName  +   ": "   +  msg );
     }

     public   static   void  main ( String []  args )   {
         final   BothInMethod  bim  =   new   BothInMethod ( "obj1" );

         Runnable  runA  =   new   Runnable ()   {
                 public   void  run ()   {
                    bim . doStuff ( 3 );
                 }
             };

         Thread  threadA  =   new   Thread ( runA ,   "threadA" );
        threadA . start ();

         try   {   Thread . sleep ( 200 );   }   catch   (   InterruptedException  x  )   {   }

         Runnable  runB  =   new   Runnable ()   {
                 public   void  run ()   {
                    bim . doStuff ( 7 );
                 }
             };

         Thread  threadB  =   new   Thread ( runB ,   "threadB" );
        threadB . start ();
     }
}

source/chapter07/CleanRead.java

source/chapter07/CleanRead.java

public   class   CleanRead   extends   Object   {
     private   String  fname ;
     private   String  lname ;

     public   synchronized   String  getNames ()   {
         return  lname  +   ", "   +  fname ;
     }

     public   synchronized   void  setNames (
                 String  firstName ,  
                 String  lastName
             )   {

        print ( "entering setNames()" );
        fname  =  firstName ;

         try   {   Thread . sleep ( 1000 );   }  
         catch   (   InterruptedException  x  )   {   }

        lname  =  lastName ;
        print ( "leaving setNames() - "   +  lname  +   ", "   +  fname );
     }

     public   static   void  print ( String  msg )   {
         String  threadName  =   Thread . currentThread (). getName ();
         System . out . println ( threadName  +   ": "   +  msg );
     }

     public   static   void  main ( String []  args )   {
         final   CleanRead  cr  =   new   CleanRead ();
        cr . setNames ( "George" ,   "Washington" );   // initially

         Runnable  runA  =   new   Runnable ()   {
                 public   void  run ()   {
                    cr . setNames ( "Abe" ,   "Lincoln" );
                 }
             };

         Thread  threadA  =   new   Thread ( runA ,   "threadA" );
        threadA . start ();

         try   {   Thread . sleep ( 200 );   }  
         catch   (   InterruptedException  x  )   {   }

         Runnable  runB  =   new   Runnable ()   {
                 public   void  run ()   {
                    print ( "getNames()="   +  cr . getNames ());
                 }
             };

         Thread  threadB  =   new   Thread ( runB ,   "threadB" );
        threadB . start ();
     }
}

source/chapter07/CorruptWrite.java

source/chapter07/CorruptWrite.java

public   class   CorruptWrite   extends   Object   {
     private   String  fname ;
     private   String  lname ;

     public   void  setNames ( String  firstName ,   String  lastName )   {
        print ( "entering setNames()" );
        fname  =  firstName ;

         // A thread might be swapped out here, and may stay 
         // out for a varying amount of time. The different 
         // sleep times exaggerate this.
         if   (  fname . length ()   <   5   )   {
             try   {   Thread . sleep ( 1000 );   }  
             catch   (   InterruptedException  x  )   {   }
         }   else   {
             try   {   Thread . sleep ( 2000 );   }  
             catch   (   InterruptedException  x  )   {   }
         }

        lname  =  lastName ;

        print ( "leaving setNames() - "   +  lname  +   ", "   +  fname );
     }

     public   static   void  print ( String  msg )   {
         String  threadName  =   Thread . currentThread (). getName ();
         System . out . println ( threadName  +   ": "   +  msg );
     }

     public   static   void  main ( String []  args )   {
         final   CorruptWrite  cw  =   new   CorruptWrite ();

         Runnable  runA  =   new   Runnable ()   {
                 public   void  run ()   {
                    cw . setNames ( "George" ,   "Washington" );
                 }
             };

         Thread  threadA  =   new   Thread ( runA ,   "threadA" );
        threadA . start ();

         try   {   Thread . sleep ( 200 );   }  
         catch   (   InterruptedException  x  )   {   }

         Runnable  runB  =   new   Runnable ()   {
                 public   void  run ()   {
                    cw . setNames ( "Abe" ,   "Lincoln" );
                 }
             };

         Thread  threadB  =   new   Thread ( runB ,   "threadB" );
        threadB . start ();
     }
}

source/chapter07/Deadlock.java

source/chapter07/Deadlock.java

public   class   Deadlock   extends   Object   {
     private   String  objID ;

     public   Deadlock ( String  id )   {
        objID  =  id ;
     }

     public   synchronized   void  checkOther ( Deadlock  other )   {
        print ( "entering checkOther()" );

         // simulate some lengthy process
         try   {   Thread . sleep ( 2000 );   }  
         catch   (   InterruptedException  x  )   {   }

        print ( "in checkOther() - about to "   +
                 "invoke 'other.action()'" );
        other . action ();

        print ( "leaving checkOther()" );
     }

     public   synchronized   void  action ()   {
        print ( "entering action()" );

         // simulate some work here
         try   {   Thread . sleep ( 500 );   }  
         catch   (   InterruptedException  x  )   {   }

        print ( "leaving action()" );
     }

     public   void  print ( String  msg )   {
        threadPrint ( "objID="   +  objID  +   " - "   +  msg );
     }

     public   static   void  threadPrint ( String  msg )   {
         String  threadName  =   Thread . currentThread (). getName ();
         System . out . println ( threadName  +   ": "   +  msg );
     }

     public   static   void  main ( String []  args )   {
         final   Deadlock  obj1  =   new   Deadlock ( "obj1" );
         final   Deadlock  obj2  =   new   Deadlock ( "obj2" );

         Runnable  runA  =   new   Runnable ()   {
                 public   void  run ()   {
                    obj1 . checkOther ( obj2 );
                 }
             };

         Thread  threadA  =   new   Thread ( runA ,   "threadA" );
        threadA . start ();

         try   {   Thread . sleep ( 200 );   }  
         catch   (   InterruptedException  x  )   {   }

         Runnable  runB  =   new   Runnable ()   {
                 public   void  run ()   {
                    obj2 . checkOther ( obj1 );
                 }
             };

         Thread  threadB  =   new   Thread ( runB ,   "threadB" );
        threadB . start ();

         try   {   Thread . sleep ( 5000 );   }  
         catch   (   InterruptedException  x  )   {   }

        threadPrint ( "finished sleeping" );

        threadPrint ( "about to interrupt() threadA" );
        threadA . interrupt ();

         try   {   Thread . sleep ( 1000 );   }  
         catch   (   InterruptedException  x  )   {   }

        threadPrint ( "about to interrupt() threadB" );
        threadB . interrupt ();

         try   {   Thread . sleep ( 1000 );   }  
         catch   (   InterruptedException  x  )   {   }

        threadPrint ( "did that break the deadlock?" );
     }
}

source/chapter07/DirtyRead.java

source/chapter07/DirtyRead.java

public   class   DirtyRead   extends   Object   {
     private   String  fname ;
     private   String  lname ;

     public   String  getNames ()   {
         return  lname  +   ", "   +  fname ;
     }

     public   synchronized   void  setNames (
                 String  firstName ,  
                 String  lastName
             )   {

        print ( "entering setNames()" );
        fname  =  firstName ;

         try   {   Thread . sleep ( 1000 );   }  
         catch   (   InterruptedException  x  )   {   }

        lname  =  lastName ;
        print ( "leaving setNames() - "   +  lname  +   ", "   +  fname );
     }

     public   static   void  print ( String  msg )   {
         String  threadName  =   Thread . currentThread (). getName ();
         System . out . println ( threadName  +   ": "   +  msg );
     }

     public   static   void  main ( String []  args )   {
         final   DirtyRead  dr  =   new   DirtyRead ();
        dr . setNames ( "George" ,   "Washington" );   // initially 

         Runnable  runA  =   new   Runnable ()   {
                 public   void  run ()   {
                    dr . setNames ( "Abe" ,   "Lincoln" );
                 }
             };

         Thread  threadA  =   new   Thread ( runA ,   "threadA" );
        threadA . start ();

         try   {   Thread . sleep ( 200 );   }  
         catch   (   InterruptedException  x  )   {   }

         Runnable  runB  =   new   Runnable ()   {
                 public   void  run ()   {
                    print ( "getNames()="   +  dr . getNames ());
                 }
             };

         Thread  threadB  =   new   Thread ( runB ,   "threadB" );
        threadB . start ();
     }
}

source/chapter07/FixedWrite.java

source/chapter07/FixedWrite.java

public   class   FixedWrite   extends   Object   {
     private   String  fname ;
     private   String  lname ;

     public   synchronized   void  setNames (
                 String  firstName ,  
                 String  lastName
             )   {

        print ( "entering setNames()" );
        fname  =  firstName ;

         // A thread might be swapped out here, and may stay 
         // out for a varying amount of time. The different 
         // sleep times exaggerate this.
         if   (  fname . length ()   <   5   )   {
             try   {   Thread . sleep ( 1000 );   }  
             catch   (   InterruptedException  x  )   {   }
         }   else   {
             try   {   Thread . sleep ( 2000 );   }  
             catch   (   InterruptedException  x  )   {   }
         }

        lname  =  lastName ;

        print ( "leaving setNames() - "   +  lname  +   ", "   +  fname );
     }

     public   static   void  print ( String  msg )   {
         String  threadName  =   Thread . currentThread (). getName ();
         System . out . println ( threadName  +   ": "   +  msg );
     }

     public   static   void  main ( String []  args )   {
         final   FixedWrite  fw  =   new   FixedWrite ();

         Runnable  runA  =   new   Runnable ()   {
                 public   void  run ()   {
                    fw . setNames ( "George" ,   "Washington" );
                 }
             };

         Thread  threadA  =   new   Thread ( runA ,   "threadA" );
        threadA . start ();

         try   {   Thread . sleep ( 200 );   }  
         catch   (   InterruptedException  x  )   {   }

         Runnable  runB  =   new   Runnable ()   {
                 public   void  run ()   {
                    fw . setNames ( "Abe" ,   "Lincoln" );
                 }
             };

         Thread  threadB  =   new   Thread ( runB ,   "threadB" );
        threadB . start ();
     }
}

source/chapter07/OnlyOneInMethod.java

source/chapter07/OnlyOneInMethod.java

public   class   OnlyOneInMethod   extends   Object   {
     private   String  objID ;

     public   OnlyOneInMethod ( String  objID )   {
         this . objID  =  objID ;
     }

     public   synchronized   void  doStuff ( int  val )   {
        print ( "entering doStuff()" );
         int  num  =  val  *   2   +  objID . length ();
        print ( "in doStuff() - local variable num="   +  num );

         // slow things down to make observations
         try   {   Thread . sleep ( 2000 );   }   catch   (   InterruptedException  x  )   {   }

        print ( "leaving doStuff()" );
     }

     public   void  print ( String  msg )   {
        threadPrint ( "objID="   +  objID  +   " - "   +  msg );
     }

     public   static   void  threadPrint ( String  msg )   {
         String  threadName  =   Thread . currentThread (). getName ();
         System . out . println ( threadName  +   ": "   +  msg );
     }

     public   static   void  main ( String []  args )   {
         final   OnlyOneInMethod  ooim  =   new   OnlyOneInMethod ( "obj1" );

         Runnable  runA  =   new   Runnable ()   {
                 public   void  run ()   {
                    ooim . doStuff ( 3 );
                 }
             };

         Thread  threadA  =   new   Thread ( runA ,   "threadA" );
        threadA . start ();

         try   {   Thread . sleep ( 200 );   }   catch   (   InterruptedException  x  )   {   }

         Runnable  runB  =   new   Runnable ()   {
                 public   void  run ()   {
                    ooim . doStuff ( 7 );
                 }
             };

         Thread  threadB  =   new   Thread ( runB ,   "threadB" );
        threadB . start ();
     }
}

source/chapter07/SafeCollectionIteration.java

source/chapter07/SafeCollectionIteration.java

import  java . util . * ;

public   class   SafeCollectionIteration   extends   Object   {
     public   static   void  main ( String []  args )   {
         // To be safe, only keep a reference to the 
         // *synchronized* list so that you are sure 
         // that all accesses are controlled.

         // The collection *must* be synchronized 
         // (a List in this case).
         List  wordList  =  
                 Collections . synchronizedList ( new   ArrayList ());

        wordList . add ( "Iterators" );
        wordList . add ( "require" );
        wordList . add ( "special" );
        wordList . add ( "handling" );

         // All of this must be in a synchronized block to 
         // block other threads from modifying wordList while 
         // the iteration is in progress.
         synchronized   (  wordList  )   {
             Iterator  iter  =  wordList . iterator ();
             while   (  iter . hasNext ()   )   {
                 String  s  =   ( String )  iter . next ();
                 System . out . println ( "found string: "   +  s  +  
                     ", length="   +  s . length ());
             }
         }
     }
}

source/chapter07/SafeListCopy.java

source/chapter07/SafeListCopy.java

import  java . util . * ;

public   class   SafeListCopy   extends   Object   {
     public   static   void  printWords ( String []  word )   {
         System . out . println ( "word.length="   +  word . length );
         for   (   int  i  =   0 ;  i  <  word . length ;  i ++   )   {
             System . out . println ( "word["   +  i  +   "]="   +  word [ i ]);
         }
     }

     public   static   void  main ( String []  args )   {
         // To be safe, only keep a reference to the 
         // *synchronized* list so that you are sure that 
         // all accesses are controlled.
         List  wordList  =  
                 Collections . synchronizedList ( new   ArrayList ());

        wordList . add ( "Synchronization" );
        wordList . add ( "is" );
        wordList . add ( "important" );

         // First technique (favorite)
         String []  wordA  =  
                 ( String [])  wordList . toArray ( new   String [ 0 ]);

        printWords ( wordA );

         // Second technique
         String []  wordB ;
         synchronized   (  wordList  )   {
             int  size  =  wordList . size ();
            wordB  =   new   String [ size ];
            wordList . toArray ( wordB );
         }

        printWords ( wordB );

         // Third technique (the 'synchronized' *is* necessary)
         String []  wordC ;
         synchronized   (  wordList  )   {
            wordC  =   ( String [])  wordList . toArray (
                                 new   String [ wordList . size ()]);
         }

        printWords ( wordC );
     }
}

source/chapter07/SafeVectorCopy.java

source/chapter07/SafeVectorCopy.java

import  java . util . * ;

public   class   SafeVectorCopy   extends   Object   {
     public   static   void  main ( String []  args )   {
         Vector  vect  =   new   Vector ();
        vect . addElement ( "Synchronization" );
        vect . addElement ( "is" );
        vect . addElement ( "important" );

         String []  word ;

         synchronized   (  vect  )   {
             int  size  =  vect . size ();
            word  =   new   String [ size ];

             for   (   int  i  =   0 ;  i  <  word . length ;  i ++   )   {
                word [ i ]   =   ( String )  vect . elementAt ( i );
             }
         }

         System . out . println ( "word.length="   +  word . length );
         for   (   int  i  =   0 ;  i  <  word . length ;  i ++   )   {
             System . out . println ( "word["   +  i  +   "]="   +  word [ i ]);
         }
     }
}

source/chapter07/StaticBlock.java

source/chapter07/StaticBlock.java

public   class   StaticBlock   extends   Object   {
     public   static   synchronized   void  staticA ()   {
         System . out . println ( "entering staticA()" );

         try   {   Thread . sleep ( 5000 );   }  
         catch   (   InterruptedException  x  )   {   }

         System . out . println ( "leaving staticA()" );
     }

     public   static   void  staticB ()   {
         System . out . println ( "entering staticB()" );

         synchronized   (   StaticBlock . class   )   {
             System . out . println (
                     "in staticB() - inside sync block" );

             try   {   Thread . sleep ( 2000 );   }  
             catch   (   InterruptedException  x  )   {   }
         }

         System . out . println ( "leaving staticB()" );
     }

     public   static   void  main ( String []  args )   {
         Runnable  runA  =   new   Runnable ()   {
                 public   void  run ()   {
                     StaticBlock . staticA ();
                 }
             };

         Thread  threadA  =   new   Thread ( runA ,   "threadA" );
        threadA . start ();

         try   {   Thread . sleep ( 200 );   }  
         catch   (   InterruptedException  x  )   {   }

         Runnable  runB  =   new   Runnable ()   {
                 public   void  run ()   {
                     StaticBlock . staticB ();
                 }
             };

         Thread  threadB  =   new   Thread ( runB ,   "threadB" );
        threadB . start ();
     }
}

source/chapter07/StaticNeedSync.java

source/chapter07/StaticNeedSync.java

public   class   StaticNeedSync   extends   Object   {
     private   static   int  nextSerialNum  =   10001 ;

     public   static   int  getNextSerialNum ()   {
         int  sn  =  nextSerialNum ;

         // Simulate a delay that is possible if the thread 
         // scheduler chooses to swap this thread off the 
         // processor at this point. The delay is exaggerated 
         // for demonstration purposes.
         try   {   Thread . sleep ( 1000 );   }  
         catch   (   InterruptedException  x  )   {   }

        nextSerialNum ++ ;
         return  sn ;
     }

     private   static   void  print ( String  msg )   {
         String  threadName  =   Thread . currentThread (). getName ();
         System . out . println ( threadName  +   ": "   +  msg );
     }

     public   static   void  main ( String []  args )   {
         try   {
             Runnable  r  =   new   Runnable ()   {
                     public   void  run ()   {
                        print ( "getNextSerialNum()="   +  
                                getNextSerialNum ());
                     }
                 };
            
             Thread  threadA  =   new   Thread ( r ,   "threadA" );
            threadA . start ();
    
             Thread . sleep ( 1500 );  
    
             Thread  threadB  =   new   Thread ( r ,   "threadB" );
            threadB . start ();
    
             Thread . sleep ( 500 );  
    
             Thread  threadC  =   new   Thread ( r ,   "threadC" );
            threadC . start ();
    
             Thread . sleep ( 2500 );  

             Thread  threadD  =   new   Thread ( r ,   "threadD" );
            threadD . start ();
         }   catch   (   InterruptedException  x  )   {
             // ignore
         }
     }
}

source/chapter07/StaticSync.java

source/chapter07/StaticSync.java

public   class   StaticSync   extends   Object   {
     private   static   int  nextSerialNum  =   10001 ;

     public   static   synchronized   int  getNextSerialNum ()   {
         int  sn  =  nextSerialNum ;

         // Simulate a delay that is possible if the thread 
         // scheduler chooses to swap this thread off the 
         // processor at this point. The delay is exaggerated 
         // for demonstration purposes.
         try   {   Thread . sleep ( 1000 );   }  
         catch   (   InterruptedException  x  )   {   }

        nextSerialNum ++ ;
         return  sn ;
     }

     private   static   void  print ( String  msg )   {
         String  threadName  =   Thread . currentThread (). getName ();
         System . out . println ( threadName  +   ": "   +  msg );
     }

     public   static   void  main ( String []  args )   {
         try   {
             Runnable  r  =   new   Runnable ()   {
                     public   void  run ()   {
                        print ( "getNextSerialNum()="   +  
                                getNextSerialNum ());
                     }
                 };
            
             Thread  threadA  =   new   Thread ( r ,   "threadA" );
            threadA . start ();
    
             Thread . sleep ( 1500 );  
    
             Thread  threadB  =   new   Thread ( r ,   "threadB" );
            threadB . start ();
    
             Thread . sleep ( 500 );  
    
             Thread  threadC  =   new   Thread ( r ,   "threadC" );
            threadC . start ();
    
             Thread . sleep ( 2500 );  

             Thread  threadD  =   new   Thread ( r ,   "threadD" );
            threadD . start ();
         }   catch   (   InterruptedException  x  )   {
             // ignore
         }
     }
}

source/chapter07/TwoObjects.java

source/chapter07/TwoObjects.java

public   class   TwoObjects   extends   Object   {
     private   String  objID ;

     public   TwoObjects ( String  objID )   {
         this . objID  =  objID ;
     }

     public   synchronized   void  doStuff ( int  val )   {
        print ( "entering doStuff()" );
         int  num  =  val  *   2   +  objID . length ();
        print ( "in doStuff() - local variable num="   +  num );

         // slow things down to make observations
         try   {   Thread . sleep ( 2000 );   }   catch   (   InterruptedException  x  )   {   }

        print ( "leaving doStuff()" );
     }

     public   void  print ( String  msg )   {
        threadPrint ( "objID="   +  objID  +   " - "   +  msg );
     }

     public   static   void  threadPrint ( String  msg )   {
         String  threadName  =   Thread . currentThread (). getName ();
         System . out . println ( threadName  +   ": "   +  msg );
     }

     public   static   void  main ( String []  args )   {
         final   TwoObjects  obj1  =   new   TwoObjects ( "obj1" );
         final   TwoObjects  obj2  =   new   TwoObjects ( "obj2" );

         Runnable  runA  =   new   Runnable ()   {
                 public   void  run ()   {
                    obj1 . doStuff ( 3 );
                 }
             };

         Thread  threadA  =   new   Thread ( runA ,   "threadA" );
        threadA . start ();

         try   {   Thread . sleep ( 200 );   }   catch   (   InterruptedException  x  )   {   }

         Runnable  runB  =   new   Runnable ()   {
                 public   void  run ()   {
                    obj2 . doStuff ( 7 );
                 }
             };

         Thread  threadB  =   new   Thread ( runB ,   "threadB" );
        threadB . start ();
     }
}

source/chapter07/Volatile.java

source/chapter07/Volatile.java

public   class   Volatile   extends   Object   implements   Runnable   {
     // not marked as 'volatile', but it should be!
     private   int  value ;   

     private   volatile   boolean  missedIt ;

     // doesn't need to be volatile-doesn't change
     private   long  creationTime ;  

     public   Volatile ()   {
        value  =   10 ;
        missedIt  =   false ;
        creationTime  =   System . currentTimeMillis ();
     }

     public   void  run ()   {
        print ( "entering run()" );

         // each time, check to see if 'value' is different
         while   (  value  <   20   )   {

             // Used to break out of the loop if change to 
             // value is missed.
             if    (  missedIt  )   {
                 int  currValue  =  value ;

                 // Simply execute a synchronized statement on an
                 // arbitrary object to see the effect.
                 Object  lock  =   new   Object ();
                 synchronized   (  lock  )   {
                     // do nothing!
                 }

                 int  valueAfterSync  =  value ;

                print ( "in run() - see value="   +  currValue  +
                     ", but rumor has it that it changed!" );
                print ( "in run() - valueAfterSync="   +  
                    valueAfterSync );

                 break ;  
             }
         }

        print ( "leaving run()" );
     }

     public   void  workMethod ()   throws   InterruptedException   {
        print ( "entering workMethod()" );

        print ( "in workMethod() - about to sleep for 2 seconds" );
         Thread . sleep ( 2000 );

        value  =   50 ;
        print ( "in workMethod() - just set value="   +  value );

        print ( "in workMethod() - about to sleep for 5 seconds" );
         Thread . sleep ( 5000 );

        missedIt  =   true ;
        print ( "in workMethod() - just set missedIt="   +  missedIt );

        print ( "in workMethod() - about to sleep for 3 seconds" );
         Thread . sleep ( 3000 );

        print ( "leaving workMethod()" );
     }

     private   void  print ( String  msg )   {
         // This method could have been simplified by using 
         // functionality present in the java.text package, 
         // but did not take advantage of it since that package 
         // is not present in JDK1.0.

         long  interval  =   System . currentTimeMillis ()   -  
                        creationTime ;

         String  tmpStr  =   "    "   +   (  interval  /   1000.0   )   +   "000" ;
        
         int  pos  =  tmpStr . indexOf ( "." );
         String  secStr  =  tmpStr . substring ( pos  -   2 ,  pos  +   4 );

         String  nameStr  =   "        "   +  
                 Thread . currentThread (). getName ();

        nameStr  =  nameStr . substring ( nameStr . length ()   -   8 ,  
                                    nameStr . length ());
        
         System . out . println ( secStr  +   " "   +  nameStr  +   ": "   +  msg );
     }

     public   static   void  main ( String []  args )   {
         try   {
             Volatile  vol  =   new   Volatile ();

             // slight pause to let some time elapse
             Thread . sleep ( 100 );   

             Thread  t  =   new   Thread ( vol );
            t . start ();

             // slight pause to allow run() to go first
             Thread . sleep ( 100 );   

            vol . workMethod ();
         }   catch   (   InterruptedException  x  )   {
             System . err . println (
                 "one of the sleeps was interrupted" );
         }
     }
}

source/chapter08/CubbyHole.java

source/chapter08/CubbyHole.java

public   class   CubbyHole   extends   Object   {
     private   Object  slot ;

     public   CubbyHole ()   {
        slot  =   null ;   // null indicates empty
     }

     public   synchronized   void  putIn ( Object  obj )  
                         throws   InterruptedException   {

        print ( "in putIn() - entering" );

         while   (  slot  !=   null   )   {
            print ( "in putIn() - occupied, about to wait()" );
            wait ();   // wait while slot is occupied
            print ( "in putIn() - notified, back from wait()" );
         }

        slot  =  obj ;    // put object into slot
        print ( "in putIn() - filled slot, about to notifyAll()" );
        notifyAll ();   // signal that slot has been filled

        print ( "in putIn() - leaving" );
     }

     public   synchronized   Object  takeOut ()  
                         throws   InterruptedException   {

        print ( "in takeOut() - entering" );

         while   (  slot  ==   null   )   {
            print ( "in takeOut() - empty, about to wait()" );
            wait ();   // wait while slot is empty
            print ( "in takeOut() - notified, back from wait()" );
         }

         Object  obj  =  slot ;
        slot  =   null ;   // mark slot as empty
        print (
             "in takeOut() - emptied slot, about to notifyAll()" );
        notifyAll ();   // signal that slot is empty

        print ( "in takeOut() - leaving" );
         return  obj ;
     }

     private   static   void  print ( String  msg )   {
         String  name  =   Thread . currentThread (). getName ();
         System . out . println ( name  +   ": "   +  msg );
     }
}

source/chapter08/CubbyHoleMain.java

source/chapter08/CubbyHoleMain.java

public   class   CubbyHoleMain   extends   Object   {
     private   static   void  print ( String  msg )   {
         String  name  =   Thread . currentThread (). getName ();
         System . out . println ( name  +   ": "   +  msg );
     }

     public   static   void  main ( String []  args )   {
         final   CubbyHole  ch  =   new   CubbyHole ();

         Runnable  runA  =   new   Runnable ()   {
                 public   void  run ()   {
                     try   {
                         String  str ;
                         Thread . sleep ( 500 );

                        str  =   "multithreaded" ;
                        ch . putIn ( str );
                        print ( "in run() - just put in: '"   +  
                                str  +   "'" );

                        str  =   "programming" ;
                        ch . putIn ( str );
                        print ( "in run() - just put in: '"   +  
                                str  +   "'" );

                        str  =   "with Java" ;
                        ch . putIn ( str );
                        print ( "in run() - just put in: '"   +  
                                str  +   "'" );
                     }   catch   (   InterruptedException  x  )   {
                        x . printStackTrace ();
                     }
                 }
             };

         Runnable  runB  =   new   Runnable ()   {
                 public   void  run ()   {
                     try   {
                         Object  obj ;

                        obj  =  ch . takeOut ();
                        print ( "in run() - just took out: '"   +  
                                obj  +   "'" );

                         Thread . sleep ( 500 );

                        obj  =  ch . takeOut ();
                        print ( "in run() - just took out: '"   +  
                                obj  +   "'" );

                        obj  =  ch . takeOut ();
                        print ( "in run() - just took out: '"   +  
                                obj  +   "'" );
                     }   catch   (   InterruptedException  x  )   {
                        x . printStackTrace ();
                     }
                 }
             };

         Thread  threadA  =   new   Thread ( runA ,   "threadA" );
        threadA . start ();

         Thread  threadB  =   new   Thread ( runB ,   "threadB" );
        threadB . start ();
     }
}

source/chapter08/EarlyNotify.java

source/chapter08/EarlyNotify.java

import  java . util . * ;

public   class   EarlyNotify   extends   Object   {
     private   List  list ;

     public   EarlyNotify ()   {
        list  =   Collections . synchronizedList ( new   LinkedList ());
     }

     public   String  removeItem ()   throws   InterruptedException   {
        print ( "in removeItem() - entering" );

         synchronized   (  list  )   {
             if   (  list . isEmpty ()   )   {    // dangerous to use 'if'!
                print ( "in removeItem() - about to wait()" );
                list . wait ();
                print ( "in removeItem() - done with wait()" );
             }

             // extract the new first item
             String  item  =   ( String )  list . remove ( 0 );

            print ( "in removeItem() - leaving" );
             return  item ;
         }
     }

     public   void  addItem ( String  item )   {
        print ( "in addItem() - entering" );
         synchronized   (  list  )   {
             // There'll always be room to add to this List 
             // because it expands as needed. 
            list . add ( item );
            print ( "in addItem() - just added: '"   +  item  +   "'" );

             // After adding, notify any and all waiting 
             // threads that the list has changed.
            list . notifyAll ();
            print ( "in addItem() - just notified" );
         }
        print ( "in addItem() - leaving" );
     }

     private   static   void  print ( String  msg )   {
         String  name  =   Thread . currentThread (). getName ();
         System . out . println ( name  +   ": "   +  msg );
     }

     public   static   void  main ( String []  args )   {
         final   EarlyNotify  en  =   new   EarlyNotify ();

         Runnable  runA  =   new   Runnable ()   {
                 public   void  run ()   {
                     try   {
                         String  item  =  en . removeItem ();
                        print ( "in run() - returned: '"   +  
                                item  +   "'" );
                     }   catch   (   InterruptedException  ix  )   {
                        print ( "interrupted!" );
                     }   catch   (   Exception  x  )   {
                        print ( "threw an Exception!!!\n"   +  x );
                     }
                 }
             };

         Runnable  runB  =   new   Runnable ()   {
                 public   void  run ()   {
                    en . addItem ( "Hello!" );
                 }
             };

         try   {
             Thread  threadA1  =   new   Thread ( runA ,   "threadA1" );
            threadA1 . start ();

             Thread . sleep ( 500 );
    
             // start a *second* thread trying to remove
             Thread  threadA2  =   new   Thread ( runA ,   "threadA2" );
            threadA2 . start ();

             Thread . sleep ( 500 );
    
             Thread  threadB  =   new   Thread ( runB ,   "threadB" );
            threadB . start ();

             Thread . sleep ( 10000 );   // wait 10 seconds

            threadA1 . interrupt ();
            threadA2 . interrupt ();
         }   catch   (   InterruptedException  x  )   {
             // ignore
         }
     }
}

source/chapter08/EarlyNotifyFix.java

source/chapter08/EarlyNotifyFix.java

import  java . util . * ;

public   class   EarlyNotifyFix   extends   Object   {
     private   List  list ;

     public   EarlyNotifyFix ()   {
        list  =   Collections . synchronizedList ( new   LinkedList ());
     }

     public   String  removeItem ()   throws   InterruptedException   {
        print ( "in removeItem() - entering" );

         synchronized   (  list  )   {
             while   (  list . isEmpty ()   )   {
                print ( "in removeItem() - about to wait()" );
                list . wait ();
                print ( "in removeItem() - done with wait()" );
             }

             // extract the new first item
             String  item  =   ( String )  list . remove ( 0 );

            print ( "in removeItem() - leaving" );
             return  item ;
         }
     }

     public   void  addItem ( String  item )   {
        print ( "in addItem() - entering" );
         synchronized   (  list  )   {
             // There'll always be room to add to this List 
             // because it expands as needed. 
            list . add ( item );
            print ( "in addItem() - just added: '"   +  item  +   "'" );

             // After adding, notify any and all waiting 
             // threads that the list has changed.
            list . notifyAll ();
            print ( "in addItem() - just notified" );
         }
        print ( "in addItem() - leaving" );
     }

     private   static   void  print ( String  msg )   {
         String  name  =   Thread . currentThread (). getName ();
         System . out . println ( name  +   ": "   +  msg );
     }

     public   static   void  main ( String []  args )   {
         final   EarlyNotifyFix  enf  =   new   EarlyNotifyFix ();

         Runnable  runA  =   new   Runnable ()   {
                 public   void  run ()   {
                     try   {
                         String  item  =  enf . removeItem ();
                        print ( "in run() - returned: '"   +  
                                item  +   "'" );
                     }   catch   (   InterruptedException  ix  )   {
                        print ( "interrupted!" );
                     }   catch   (   Exception  x  )   {
                        print ( "threw an Exception!!!\n"   +  x );
                     }
                 }
             };

         Runnable  runB  =   new   Runnable ()   {
                 public   void  run ()   {
                    enf . addItem ( "Hello!" );
                 }
             };

         try   {
             Thread  threadA1  =   new   Thread ( runA ,   "threadA1" );
            threadA1 . start ();

             Thread . sleep ( 500 );
    
             // start a *second* thread trying to remove
             Thread  threadA2  =   new   Thread ( runA ,   "threadA2" );
            threadA2 . start ();

             Thread . sleep ( 500 );
    
             Thread  threadB  =   new   Thread ( runB ,   "threadB" );
            threadB . start ();

             Thread . sleep ( 10000 );   // wait 10 seconds

            threadA1 . interrupt ();
            threadA2 . interrupt ();
         }   catch   (   InterruptedException  x  )   {
             // ignore
         }
     }
}

source/chapter08/InheritableThreadID.java

source/chapter08/InheritableThreadID.java

public   class   InheritableThreadID   extends   Object   {
     public   static   final   int  UNIQUE   =   101 ;
     public   static   final   int  INHERIT  =   102 ;
     public   static   final   int  SUFFIX   =   103 ;

     private   ThreadLocal  threadLocal ;
     private   int  nextID ;

     public   InheritableThreadID ( int  type )   {
        nextID  =   201 ;

         switch   (  type  )   {
             case  UNIQUE :
                threadLocal  =   new   ThreadLocal ()   {
                         // override from ThreadLocal
                         protected   Object  initialValue ()   {
                            print ( "in initialValue()" );
                             return  getNewID ();
                         }
                     };
                 break ;

             case  INHERIT :
                threadLocal  =   new   InheritableThreadLocal ()   {
                         // override from ThreadLocal
                         protected   Object  initialValue ()   {
                            print ( "in initialValue()" );
                             return  getNewID ();
                         }
                     };
                 break ;

             case  SUFFIX :
                threadLocal  =   new   InheritableThreadLocal ()   {
                         // override from ThreadLocal
                         protected   Object  initialValue ()   {
                            print ( "in initialValue()" );
                             return  getNewID ();
                         }

                         // override from InheritableThreadLocal
                         protected   Object  childValue (
                                     Object  parentValue
                                 )   {

                            print ( "in childValue() - "   +
                                 "parentValue="   +  parentValue );

                             return  parentValue  +   "-CH" ;
                         }
                     };
                 break ;
             default :
                 break ;
         }
     }

     private   synchronized   String  getNewID ()   {
         String  id  =   "ID"   +  nextID ;
        nextID ++ ;
         return  id ;
     }

     public   String  getID ()   {
         return   ( String )  threadLocal . get ();
     }

     public   static   void  print ( String  msg )   {
         String  name  =   Thread . currentThread (). getName ();
         System . out . println ( name  +   ": "   +  msg );
     }

     public   static   Runnable  createTarget ( InheritableThreadID  id )   {
         final   InheritableThreadID  var  =  id ;

         Runnable  parentRun  =   new   Runnable ()   {
             public   void  run ()   {
                print ( "var.getID()="   +  var . getID ());
                print ( "var.getID()="   +  var . getID ());
                print ( "var.getID()="   +  var . getID ());

                 Runnable  childRun  =   new   Runnable ()   {
                         public   void  run ()   {
                            print ( "var.getID()="   +  var . getID ());
                            print ( "var.getID()="   +  var . getID ());
                            print ( "var.getID()="   +  var . getID ());
                         }
                     };

                 Thread  parentT  =   Thread . currentThread ();
                 String  parentName  =  parentT . getName ();
                print ( "creating a child thread of "   +
                    parentName );

                 Thread  childT  =   new   Thread ( childRun ,  
                        parentName  +   "-child" );
                childT . start ();
             }
         };

         return  parentRun ;
     }

     public   static   void  main ( String []  args )   {
         try   {
             System . out . println ( "======= ThreadLocal =======" );
             InheritableThreadID  varA  =  
                 new   InheritableThreadID ( UNIQUE );

             Runnable  targetA  =  createTarget ( varA );
             Thread  threadA  =   new   Thread ( targetA ,   "threadA" );
            threadA . start ();

             Thread . sleep ( 2500 );
             System . out . println ( "\n======= "   +
                 "InheritableThreadLocal =======" );

             InheritableThreadID  varB  =  
                 new   InheritableThreadID ( INHERIT );

             Runnable  targetB  =  createTarget ( varB );
             Thread  threadB  =   new   Thread ( targetB ,   "threadB" );
            threadB . start ();

             Thread . sleep ( 2500 );
             System . out . println ( "\n======= "   +
                 "InheritableThreadLocal - custom childValue()"   +
                 " =======" );

             InheritableThreadID  varC  =  
                 new   InheritableThreadID ( SUFFIX );

             Runnable  targetC  =  createTarget ( varC );
             Thread  threadC  =   new   Thread ( targetC ,   "threadC" );
            threadC . start ();
         }   catch   (   InterruptedException  x  )   {
             // ignore
         }

     }
}

source/chapter08/JoinDemo.java

source/chapter08/JoinDemo.java

public   class   JoinDemo   extends   Object   {
     public   static   Thread  launch ( String  name ,   long  napTime )   {
         final   long  sleepTime  =  napTime ;

         Runnable  r  =   new   Runnable ()   {
                 public   void  run ()   {
                     try   {
                        print ( "in run() - entering" );
                         Thread . sleep ( sleepTime );
                     }   catch   (   InterruptedException  x  )   {
                        print ( "interrupted!" );
                     }   finally   {
                        print ( "in run() - leaving" );
                     }
                 }
             };
    
         Thread  t  =   new   Thread ( r ,  name );
        t . start ();

         return  t ;
     }

     private   static   void  print ( String  msg )   {
         String  name  =   Thread . currentThread (). getName ();
         System . out . println ( name  +   ": "   +  msg );
     }

     public   static   void  main ( String []  args )   {
         Thread []  t  =   new   Thread [ 3 ];

        t [ 0 ]   =  launch ( "threadA" ,   2000 );
        t [ 1 ]   =  launch ( "threadB" ,   1000 );
        t [ 2 ]   =  launch ( "threadC" ,   3000 );

         for   (   int  i  =   0 ;  i  <  t . length ;  i ++   )   {
             try   {
                 String  idxStr  =   "t["   +  i  +   "]" ;
                 String  name  =   "["   +  t [ i ]. getName ()   +   "]" ;

                print ( idxStr  +   ".isAlive()="   +  
                        t [ i ]. isAlive ()   +   " "   +  name );
                print ( "about to do: "   +  idxStr  +  
                         ".join() "   +  name );

                 long  start  =   System . currentTimeMillis ();
                t [ i ]. join ();   // wait for the thread to die
                 long  stop  =   System . currentTimeMillis ();

                print ( idxStr  +   ".join() - took "   +  
                         (  stop  -  start  )   +   " ms "   +  name );
             }   catch   (   InterruptedException  x  )   {
                print ( "interrupted waiting on #"   +  i );
             }
         }
     }
}

source/chapter08/MissedNotify.java

source/chapter08/MissedNotify.java

public   class   MissedNotify   extends   Object   {
     private   Object  proceedLock ;

     public   MissedNotify ()   {
        print ( "in MissedNotify()" );
        proceedLock  =   new   Object ();
     }

     public   void  waitToProceed ()   throws   InterruptedException   {
        print ( "in waitToProceed() - entered" );

         synchronized   (  proceedLock  )   {
            print ( "in waitToProceed() - about to wait()" );
            proceedLock . wait ();
            print ( "in waitToProceed() - back from wait()" );
         }

        print ( "in waitToProceed() - leaving" );
     }

     public   void  proceed ()   {
        print ( "in proceed() - entered" );

         synchronized   (  proceedLock  )   {
            print ( "in proceed() - about to notifyAll()" );
            proceedLock . notifyAll ();
            print ( "in proceed() - back from notifyAll()" );
         }

        print ( "in proceed() - leaving" );
     }

     private   static   void  print ( String  msg )   {
         String  name  =   Thread . currentThread (). getName ();
         System . out . println ( name  +   ": "   +  msg );
     }

     public   static   void  main ( String []  args )   {
         final   MissedNotify  mn  =   new   MissedNotify ();

         Runnable  runA  =   new   Runnable ()   {
                 public   void  run ()   {
                     try   {
                         Thread . sleep ( 1000 );
                        mn . waitToProceed ();
                     }   catch   (   InterruptedException  x  )   {
                        x . printStackTrace ();
                     }
                 }
             };

         Thread  threadA  =   new   Thread ( runA ,   "threadA" );
        threadA . start ();

         Runnable  runB  =   new   Runnable ()   {
                 public   void  run ()   {
                     try   {
                         Thread . sleep ( 500 );
                        mn . proceed ();
                     }   catch   (   InterruptedException  x  )   {
                        x . printStackTrace ();
                     }
                 }
             };

         Thread  threadB  =   new   Thread ( runB ,   "threadB" );
        threadB . start ();

         try   {  
             Thread . sleep ( 10000 );
         }   catch   (   InterruptedException  x  )   {
         }

        print ( "about to invoke interrupt() on threadA" );
        threadA . interrupt ();
     }
}

source/chapter08/MissedNotifyFix.java

source/chapter08/MissedNotifyFix.java

public   class   MissedNotifyFix   extends   Object   {
     private   Object  proceedLock ;
     private   boolean  okToProceed ;

     public   MissedNotifyFix ()   {
        print ( "in MissedNotify()" );
        proceedLock  =   new   Object ();
        okToProceed  =   false ;
     }

     public   void  waitToProceed ()   throws   InterruptedException   {
        print ( "in waitToProceed() - entered" );

         synchronized   (  proceedLock  )   {
            print ( "in waitToProceed() - entered sync block" );

             while   (  okToProceed  ==   false   )   {
                print ( "in waitToProceed() - about to wait()" );
                proceedLock . wait ();
                print ( "in waitToProceed() - back from wait()" );
             }

            print ( "in waitToProceed() - leaving sync block" );
         }

        print ( "in waitToProceed() - leaving" );
     }

     public   void  proceed ()   {
        print ( "in proceed() - entered" );

         synchronized   (  proceedLock  )   {
            print ( "in proceed() - entered sync block" );

            okToProceed  =   true ;
            print ( "in proceed() - changed okToProceed to true" );
            proceedLock . notifyAll ();
            print ( "in proceed() - just did notifyAll()" );

            print ( "in proceed() - leaving sync block" );
         }

        print ( "in proceed() - leaving" );
     }

     private   static   void  print ( String  msg )   {
         String  name  =   Thread . currentThread (). getName ();
         System . out . println ( name  +   ": "   +  msg );
     }

     public   static   void  main ( String []  args )   {
         final   MissedNotifyFix  mnf  =   new   MissedNotifyFix ();

         Runnable  runA  =   new   Runnable ()   {
                 public   void  run ()   {
                     try   {
                         Thread . sleep ( 1000 );
                        mnf . waitToProceed ();
                     }   catch   (   InterruptedException  x  )   {
                        x . printStackTrace ();
                     }
                 }
             };

         Thread  threadA  =   new   Thread ( runA ,   "threadA" );
        threadA . start ();

         Runnable  runB  =   new   Runnable ()   {
                 public   void  run ()   {
                     try   {
                         Thread . sleep ( 500 );
                        mnf . proceed ();
                     }   catch   (   InterruptedException  x  )   {
                        x . printStackTrace ();
                     }
                 }
             };

         Thread  threadB  =   new   Thread ( runB ,   "threadB" );
        threadB . start ();

         try   {  
             Thread . sleep ( 10000 );
         }   catch   (   InterruptedException  x  )   {
         }

        print ( "about to invoke interrupt() on threadA" );
        threadA . interrupt ();
     }
}

source/chapter08/PipedBytes.java

source/chapter08/PipedBytes.java

import  java . io . * ;

public   class   PipedBytes   extends   Object   {
     public   static   void  writeStuff ( OutputStream  rawOut )   {
         try   {
             DataOutputStream  out  =   new   DataOutputStream (
                     new   BufferedOutputStream ( rawOut ));
    
             int []  data  =   {   82 ,   105 ,   99 ,   104 ,   97 ,   114 ,   100 ,   32 ,  
                            72 ,   121 ,   100 ,   101   };

             for   (   int  i  =   0 ;  i  <  data . length ;  i ++   )   {
                out . writeInt ( data [ i ]);
             }

            out . flush ();
            out . close ();
         }   catch   (   IOException  x  )   {
            x . printStackTrace ();
         }
     }

     public   static   void  readStuff ( InputStream  rawIn )   {
         try   {
             DataInputStream  in  =   new   DataInputStream (
                     new   BufferedInputStream ( rawIn ));

             boolean  eof  =   false ;
             while   (   ! eof  )   {
                 try   {
                     int  i  =  in . readInt ();
                     System . out . println ( "just read: "   +  i );
                 }   catch   (   EOFException  eofx  )   {
                    eof  =   true ;
                 }
             }

             System . out . println ( "Read all data from the pipe" );
         }   catch   (   IOException  x  )   {
            x . printStackTrace ();
         }
     }

     public   static   void  main ( String []  args )   {
         try   {
             final   PipedOutputStream  out  =  
                     new   PipedOutputStream ();

             final   PipedInputStream  in  =  
                     new   PipedInputStream ( out );

             Runnable  runA  =   new   Runnable ()   {
                     public   void  run ()   {
                        writeStuff ( out );
                     }
                 };

             Thread  threadA  =   new   Thread ( runA ,   "threadA" );
            threadA . start ();
    
             Runnable  runB  =   new   Runnable ()   {
                     public   void  run ()   {
                        readStuff ( in );
                     }
                 };
    
             Thread  threadB  =   new   Thread ( runB ,   "threadB" );
            threadB . start ();
         }   catch   (   IOException  x  )   {
            x . printStackTrace ();
         }
     }
}

source/chapter08/PipedCharacters.java

source/chapter08/PipedCharacters.java

import  java . io . * ;

public   class   PipedCharacters   extends   Object   {
     public   static   void  writeStuff ( Writer  rawOut )   {
         try   {
             BufferedWriter  out  =   new   BufferedWriter ( rawOut );
    
             String [][]  line  =   {
                     {   "Java" ,   "has" ,   "nice" ,   "features."   },
                     {   "Pipes" ,   "are" ,   "interesting."   },
                     {   "Threads" ,   "are" ,   "fun" ,   "in" ,   "Java."   },
                     {   "Don't" ,   "you" ,   "think" ,   "so?"   }
                 };

             for   (   int  i  =   0 ;  i  <  line . length ;  i ++   )   {
                 String []  word  =  line [ i ];

                 for   (   int  j  =   0 ;  j  <  word . length ;  j ++   )   {
                     if   (  j  >   0   )   {
                         // put a space between words
                        out . write ( " " );
                     }  

                    out . write ( word [ j ]);
                 }

                 // mark the end of a line
                out . newLine ();
             }

            out . flush ();
            out . close ();
         }   catch   (   IOException  x  )   {
            x . printStackTrace ();
         }
     }

     public   static   void  readStuff ( Reader  rawIn )   {
         try   {
             BufferedReader  in  =   new   BufferedReader ( rawIn );

             String  line ;
             while   (   (  line  =  in . readLine ()   )   !=   null   )   {
                 System . out . println ( "read line: "   +  line );
             }

             System . out . println ( "Read all data from the pipe" );
         }   catch   (   IOException  x  )   {
            x . printStackTrace ();
         }
     }

     public   static   void  main ( String []  args )   {
         try   {
             final   PipedWriter  out  =   new   PipedWriter ();

             final   PipedReader  in  =   new   PipedReader ( out );

             Runnable  runA  =   new   Runnable ()   {
                     public   void  run ()   {
                        writeStuff ( out );
                     }
                 };

             Thread  threadA  =   new   Thread ( runA ,   "threadA" );
            threadA . start ();
    
             Runnable  runB  =   new   Runnable ()   {
                     public   void  run ()   {
                        readStuff ( in );
                     }
                 };
    
             Thread  threadB  =   new   Thread ( runB ,   "threadB" );
            threadB . start ();
         }   catch   (   IOException  x  )   {
            x . printStackTrace ();
         }
     }
}

source/chapter08/ThreadID.java

source/chapter08/ThreadID.java

public   class   ThreadID   extends   ThreadLocal   {
     private   int  nextID ;

     public   ThreadID ()   {
        nextID  =   10001 ;
     }

     private   synchronized   Integer  getNewID ()   {
         Integer  id  =   new   Integer ( nextID );
        nextID ++ ;
         return  id ;
     }

     // override ThreadLocal's version
     protected   Object  initialValue ()   {
        print ( "in initialValue()" );
         return  getNewID ();
     }

     public   int  getThreadID ()   {
         // Call get() in ThreadLocal to get the calling
         // thread's unique ID.
         Integer  id  =   ( Integer )  get ();  
         return  id . intValue ();
     }

     private   static   void  print ( String  msg )   {
         String  name  =   Thread . currentThread (). getName ();
         System . out . println ( name  +   ": "   +  msg );
     }
}

source/chapter08/ThreadIDMain.java

source/chapter08/ThreadIDMain.java

public   class   ThreadIDMain   extends   Object   implements   Runnable   {
     private   ThreadID  var ;

     public   ThreadIDMain ( ThreadID  var )   {
         this . var  =  var ;
     }

     public   void  run ()   {
         try   {  
            print ( "var.getThreadID()="   +  var . getThreadID ());
             Thread . sleep ( 2000 );  
            print ( "var.getThreadID()="   +  var . getThreadID ());
         }   catch   (   InterruptedException  x  )   {
             // ignore
         }
     }

     private   static   void  print ( String  msg )   {
         String  name  =   Thread . currentThread (). getName ();
         System . out . println ( name  +   ": "   +  msg );
     }

     public   static   void  main ( String []  args )   {
         ThreadID  tid  =   new   ThreadID ();
         ThreadIDMain  shared  =   new   ThreadIDMain ( tid );

         try   {
             Thread  threadA  =   new   Thread ( shared ,   "threadA" );
            threadA . start ();

             Thread . sleep ( 500 );

             Thread  threadB  =   new   Thread ( shared ,   "threadB" );
            threadB . start ();

             Thread . sleep ( 500 );

             Thread  threadC  =   new   Thread ( shared ,   "threadC" );
            threadC . start ();
         }   catch   (   InterruptedException  x  )   {
             // ignore
         }
     }
}

source/chapter09/BalanceLookup.java

source/chapter09/BalanceLookup.java

import  java . awt . * ;
import  java . awt . event . * ;
import  javax . swing . * ;

public   class   BalanceLookup   extends   JPanel   {
     private   JTextField  acctTF ;
     private   JTextField  pinTF ;
     private   JButton  searchB ;
     private   JButton  cancelB ;
     private   JLabel  balanceL ;

     private   volatile   Thread  lookupThread ;

     public   BalanceLookup ()   {
        buildGUI ();
        hookupEvents ();
     }

     private   void  buildGUI ()   {
         JLabel  acctL  =   new   JLabel ( "Account Number:" );
         JLabel  pinL  =   new   JLabel ( "PIN:" );
        acctTF  =   new   JTextField ( 12 );
        pinTF  =   new   JTextField ( 4 );

         JPanel  dataEntryP  =   new   JPanel ();
        dataEntryP . setLayout ( new   FlowLayout ( FlowLayout . CENTER ));
        dataEntryP . add ( acctL );
        dataEntryP . add ( acctTF );
        dataEntryP . add ( pinL );
        dataEntryP . add ( pinTF );

        searchB  =   new   JButton ( "Search" );
        cancelB  =   new   JButton ( "Cancel Search" );
        cancelB . setEnabled ( false );

         JPanel  innerButtonP  =   new   JPanel ();
        innerButtonP . setLayout ( new   GridLayout ( 1 ,   - 1 ,   5 ,   5 ));
        innerButtonP . add ( searchB );
        innerButtonP . add ( cancelB );

         JPanel  buttonP  =   new   JPanel ();
        buttonP . setLayout ( new   FlowLayout ( FlowLayout . CENTER ));
        buttonP . add ( innerButtonP );

         JLabel  balancePrefixL  =   new   JLabel ( "Account Balance:" );
        balanceL  =   new   JLabel ( "BALANCE UNKNOWN" );

         JPanel  balanceP  =   new   JPanel ();
        balanceP . setLayout ( new   FlowLayout ( FlowLayout . CENTER ));
        balanceP . add ( balancePrefixL );
        balanceP . add ( balanceL );

         JPanel  northP  =   new   JPanel ();
        northP . setLayout ( new   GridLayout ( - 1 ,   1 ,   5 ,   5 ));
        northP . add ( dataEntryP );
        northP . add ( buttonP );
        northP . add ( balanceP );

        setLayout ( new   BorderLayout ());
        add ( northP ,   BorderLayout . NORTH );
     }

     private   void  hookupEvents ()   {
        searchB . addActionListener ( new   ActionListener ()   {
                 public   void  actionPerformed ( ActionEvent  e )   {
                    search ();
                 }
             });

        cancelB . addActionListener ( new   ActionListener ()   {
                 public   void  actionPerformed ( ActionEvent  e )   {
                    cancelSearch ();
                 }
             });
     }

     private   void  search ()   {
         // better be called by event thread!
        ensureEventThread ();

        searchB . setEnabled ( false );
        cancelB . setEnabled ( true );
        balanceL . setText ( "SEARCHING ..." );

         // get a snapshot of this info in case it changes
         String  acct  =  acctTF . getText ();
         String  pin  =  pinTF . getText ();

        lookupAsync ( acct ,  pin );
     }

     private   void  lookupAsync ( String  acct ,   String  pin )   {
         // Called by event thread, but can be safely 
         // called by any thread.
         final   String  acctNum  =  acct ;
         final   String  pinNum  =  pin ;

         Runnable  lookupRun  =   new   Runnable ()   {
                 public   void  run ()   {
                     String  bal  =  lookupBalance ( acctNum ,  pinNum );
                    setBalanceSafely ( bal );
                 }
             };
        
        lookupThread  =   new   Thread ( lookupRun ,   "lookupThread" );
        lookupThread . start ();
     }
    
     private   String  lookupBalance ( String  acct ,   String  pin )   {
         // Called by lookupThread, but can be safely 
         // called by any thread.
         try   {
             // Simulate a lengthy search that takes 5 seconds
             // to communicate over the network.
             Thread . sleep ( 5000 );

             // result "retrieved", return it
             return   "1,234.56" ;
         }   catch   (   InterruptedException  x  )   {
             return   "SEARCH CANCELLED" ;
         }
     }

     private   void  setBalanceSafely ( String  newBal )   {
         // Called by lookupThread, but can be safely 
         // called by any thread.
         final   String  newBalance  =  newBal ;

         Runnable  r  =   new   Runnable ()   {
                 public   void  run ()   {
                     try   {
                        setBalance ( newBalance );
                     }   catch   (   Exception  x  )   {
                        x . printStackTrace ();
                     }
                 }
             };
        
         SwingUtilities . invokeLater ( r );
     }

     private   void  setBalance ( String  newBalance )   {
         // better be called by event thread!
        ensureEventThread ();

        balanceL . setText ( newBalance );
        cancelB . setEnabled ( false );
        searchB . setEnabled ( true );
     }

     private   void  cancelSearch ()   {
         // better be called by event thread!
        ensureEventThread ();

        cancelB . setEnabled ( false );   // prevent additional requests

         if   (  lookupThread  !=   null   )   {
            lookupThread . interrupt ();
         }
     }

     private   void  ensureEventThread ()   {
         // throws an exception if not invoked by the 
         // event thread.
         if   (   SwingUtilities . isEventDispatchThread ()   )   {
             return ;
         }

         throw   new   RuntimeException ( "only the event "   +
             "thread should invoke this method" );
     }

     public   static   void  main ( String []  args )   {
         BalanceLookup  bl  =   new   BalanceLookup ();

         JFrame  f  =   new   JFrame ( "Balance Lookup" );
        f . addWindowListener ( new   WindowAdapter ()   {
                 public   void  windowClosing ( WindowEvent  e )   {
                     System . exit ( 0 );
                 }
             });

        f . setContentPane ( bl );
        f . setSize ( 400 ,   150 );
        f . setVisible ( true );
     }
}

source/chapter09/BalanceLookupCantCancel.java

source/chapter09/BalanceLookupCantCancel.java

import  java . awt . * ;
import  java . awt . event . * ;
import  javax . swing . * ;

public   class   BalanceLookupCantCancel   extends   JPanel   {
     private   JTextField  acctTF ;
     private   JTextField  pinTF ;
     private   JButton  searchB ;
     private   JButton  cancelB ;
     private   JLabel  balanceL ;

     public   BalanceLookupCantCancel ()   {
        buildGUI ();
        hookupEvents ();
     }

     private   void  buildGUI ()   {
         JLabel  acctL  =   new   JLabel ( "Account Number:" );
         JLabel  pinL  =   new   JLabel ( "PIN:" );
        acctTF  =   new   JTextField ( 12 );
        pinTF  =   new   JTextField ( 4 );

         JPanel  dataEntryP  =   new   JPanel ();
        dataEntryP . setLayout ( new   FlowLayout ( FlowLayout . CENTER ));
        dataEntryP . add ( acctL );
        dataEntryP . add ( acctTF );
        dataEntryP . add ( pinL );
        dataEntryP . add ( pinTF );

        searchB  =   new   JButton ( "Search" );
        cancelB  =   new   JButton ( "Cancel Search" );
        cancelB . setEnabled ( false );

         JPanel  innerButtonP  =   new   JPanel ();
        innerButtonP . setLayout ( new   GridLayout ( 1 ,   - 1 ,   5 ,   5 ));
        innerButtonP . add ( searchB );
        innerButtonP . add ( cancelB );

         JPanel  buttonP  =   new   JPanel ();
        buttonP . setLayout ( new   FlowLayout ( FlowLayout . CENTER ));
        buttonP . add ( innerButtonP );

         JLabel  balancePrefixL  =   new   JLabel ( "Account Balance:" );
        balanceL  =   new   JLabel ( "BALANCE UNKNOWN" );

         JPanel  balanceP  =   new   JPanel ();
        balanceP . setLayout ( new   FlowLayout ( FlowLayout . CENTER ));
        balanceP . add ( balancePrefixL );
        balanceP . add ( balanceL );

         JPanel  northP  =   new   JPanel ();
        northP . setLayout ( new   GridLayout ( - 1 ,   1 ,   5 ,   5 ));
        northP . add ( dataEntryP );
        northP . add ( buttonP );
        northP . add ( balanceP );

        setLayout ( new   BorderLayout ());
        add ( northP ,   BorderLayout . NORTH );
     }

     private   void  hookupEvents ()   {
        searchB . addActionListener ( new   ActionListener ()   {
                 public   void  actionPerformed ( ActionEvent  e )   {
                    search ();
                 }
             });

        cancelB . addActionListener ( new   ActionListener ()   {
                 public   void  actionPerformed ( ActionEvent  e )   {
                    cancelSearch ();
                 }
             });
     }

     private   void  search ()   {
         // better be called by event thread!
        searchB . setEnabled ( false );
        cancelB . setEnabled ( true );
        balanceL . setText ( "SEARCHING ..." );

         // get a snapshot of this info in case it changes
         String  acct  =  acctTF . getText ();
         String  pin  =  pinTF . getText ();

         String  bal  =  lookupBalance ( acct ,  pin );
        setBalance ( bal );
     }

     private   String  lookupBalance ( String  acct ,   String  pin )   {
         try   {
             // Simulate a lengthy search that takes 5 seconds
             // to communicate over the network.
             Thread . sleep ( 5000 );

             // result "retrieved", return it
             return   "1,234.56" ;
         }   catch   (   InterruptedException  x  )   {
             return   "SEARCH CANCELLED" ;
         }
     }

     private   void  setBalance ( String  newBalance )   {
         // better be called by event thread!
        balanceL . setText ( newBalance );
        cancelB . setEnabled ( false );
        searchB . setEnabled ( true );
     }

     private   void  cancelSearch ()   {
         System . out . println ( "in cancelSearch()" );
         // Here's where the code to cancel would go if this
         // could ever be called!
     }

     public   static   void  main ( String []  args )   {
         BalanceLookupCantCancel  bl  =  
                 new   BalanceLookupCantCancel ();

         JFrame  f  =   new   JFrame ( "Balance Lookup - Can't Cancel" );
        f . addWindowListener ( new   WindowAdapter ()   {
                 public   void  windowClosing ( WindowEvent  e )   {
                     System . exit ( 0 );
                 }
             });

        f . setContentPane ( bl );
        f . setSize ( 400 ,   150 );
        f . setVisible ( true );
     }
}

source/chapter09/CompMover.java

source/chapter09/CompMover.java

import  java . awt . * ;
import  javax . swing . * ;

public   class   CompMover   extends   Object   {
     private   Component  comp ;
     private   int  initX ;
     private   int  initY ;
     private   int  offsetX ;
     private   int  offsetY ;
     private   boolean  firstTime ;
     private   Runnable  updatePositionRun ;

     private   Thread  internalThread ;
     private   volatile   boolean  noStopRequested ;

     public   CompMover ( Component  comp ,  
                 int  initX ,   int  initY ,
                 int  offsetX ,   int  offsetY
             )   {

         this . comp  =  comp ;
         this . initX  =  initX ;
         this . initY  =  initY ;
         this . offsetX  =  offsetX ;
         this . offsetY  =  offsetY ;

        firstTime  =   true ;

        updatePositionRun  =   new   Runnable ()   {
                 public   void  run ()   {
                    updatePosition ();
                 }
             };

        noStopRequested  =   true ;
         Runnable  r  =   new   Runnable ()   {
                 public   void  run ()   {
                     try   {
                        runWork ();
                     }   catch   (   Exception  x  )   {
                         // in case ANY exception slips through
                        x . printStackTrace ();  
                     }
                 }
             };

        internalThread  =   new   Thread ( r );
        internalThread . start ();
     }

     private   void  runWork ()   {
         while   (  noStopRequested  )   {
             try   {
                 Thread . sleep ( 200 );
                 SwingUtilities . invokeAndWait ( updatePositionRun );
             }   catch   (   InterruptedException  ix  )   {
                 // ignore
             }   catch   (   Exception  x  )   {
                x . printStackTrace ();
             }
         }
     }

     public   void  stopRequest ()   {
        noStopRequested  =   false ;
        internalThread . interrupt ();
     }

     public   boolean  isAlive ()   {
         return  internalThread . isAlive ();
     }

     private   void  updatePosition ()   {
         // should only be called by the *event* thread

         if   (   ! comp . isVisible ()   )   {
             return ;
         }

         Component  parent  =  comp . getParent ();
         if   (  parent  ==   null   )   {
             return ;
         }

         Dimension  parentSize  =  parent . getSize ();
         if   (   (  parentSize  ==   null   )   &&
              (  parentSize . width  <   1   )   &&  
              (  parentSize . height  <   1   )  
            )   {

             return ;
         }

         int  newX  =   0 ;
         int  newY  =   0 ;

         if   (  firstTime  )   {
            firstTime  =   false ;
            newX  =  initX ;
            newY  =  initY ;
         }   else   {
             Point  loc  =  comp . getLocation ();
            newX  =  loc . +  offsetX ;
            newY  =  loc . +  offsetY ;
         }

        newX  =  newX  %  parentSize . width ;
        newY  =  newY  %  parentSize . height ;

         if   (  newX  <   0   )   {
             // wrap around other side
            newX  +=  parentSize . width ;
         }

         if   (  newY  <   0   )   {
             // wrap around other side
            newY  +=  parentSize . height ;
         }

        comp . setLocation ( newX ,  newY );
        parent . repaint ();
     }

     public   static   void  main ( String []  args )   {
         Component []  comp  =   new   Component [ 6 ];

        comp [ 0 ]   =   new   ScrollText ( "Scrolling Text" );
        comp [ 1 ]   =   new   ScrollText ( "Java Threads" );
        comp [ 2 ]   =   new   SlideShow ();
        comp [ 3 ]   =   new   SlideShow ();
        comp [ 4 ]   =   new   DigitalTimer ();
        comp [ 5 ]   =   new   DigitalTimer ();

         JPanel  p  =   new   JPanel ();
        p . setLayout ( null );   // no layout manager

         for   (   int  i  =   0 ;  i  <  comp . length ;  i ++   )   {
            p . add ( comp [ i ]);

             int  x  =   ( int )   (   300   *   Math . random ()   );
             int  y  =   ( int )   (   200   *   Math . random ()   );
             int  xOff  =   2   -   ( int )   (   5   *   Math . random ()   );
             int  yOff  =   2   -   ( int )   (   5   *   Math . random ()   );

             new   CompMover ( comp [ i ],  x ,  y ,  xOff ,  yOff );
         }

         JFrame  f  =   new   JFrame ( "CompMover Demo" );
        f . setContentPane ( p );
        f . setSize ( 400 ,   300 );
        f . setVisible ( true );
     }
}

source/chapter09/DigitalTimer.java

source/chapter09/DigitalTimer.java

import  java . awt . * ;
import  java . text . * ;
import  java . lang . reflect . * ;
import  javax . swing . * ;

public   class   DigitalTimer   extends   JLabel   {
     private   volatile   String  timeText ;

     private   Thread  internalThread ;
     private   volatile   boolean  noStopRequested ;

     public   DigitalTimer ()   {
        setBorder ( BorderFactory . createLineBorder ( Color . black ));
        setHorizontalAlignment ( SwingConstants . RIGHT );
        setFont ( new   Font ( "SansSerif" ,   Font . BOLD ,   16 ));
        setText ( "00000.0" );   // use to size component
        setMinimumSize ( getPreferredSize ());
        setPreferredSize ( getPreferredSize ());
        setSize ( getPreferredSize ());

        timeText  =   "0.0" ;
        setText ( timeText );

        noStopRequested  =   true ;
         Runnable  r  =   new   Runnable ()   {
                 public   void  run ()   {
                     try   {
                        runWork ();
                     }   catch   (   Exception  x  )   {
                        x . printStackTrace ();  
                     }
                 }
             };

        internalThread  =   new   Thread ( r ,   "DigitalTimer" );
        internalThread . start ();
     }

     private   void  runWork ()   {
         long  startTime  =   System . currentTimeMillis ();
         int  tenths  =   0 ;
         long  normalSleepTime  =   100 ;
         long  nextSleepTime  =   100 ;
         DecimalFormat  fmt  =   new   DecimalFormat ( "0.0" );

         Runnable  updateText  =   new   Runnable ()   {
                 public   void  run ()   {
                    setText ( timeText );
                 }
             };

         while   (  noStopRequested  )   {
             try   {
                 Thread . sleep ( nextSleepTime );

                tenths ++ ;
                 long  currTime  =   System . currentTimeMillis ();
                 long  elapsedTime  =  currTime  -  startTime ;

                nextSleepTime  =  normalSleepTime  +  
                     (   (  tenths  *   100   )   -  elapsedTime  );

                 if   (  nextSleepTime  <   0   )   {
                    nextSleepTime  =   0 ;
                 }

                timeText  =  fmt . format ( elapsedTime  /   1000.0 );
                 SwingUtilities . invokeAndWait ( updateText );
             }   catch   (   InterruptedException  ix  )   {
                 // stop running
                 return ;
             }   catch   (   InvocationTargetException  x  )   {
                 // If an exception was thrown inside the
                 // run() method of the updateText Runnable.
                x . printStackTrace ();
             }
         }
     }

     public   void  stopRequest ()   {
        noStopRequested  =   false ;
        internalThread . interrupt ();
     }

     public   boolean  isAlive ()   {
         return  internalThread . isAlive ();
     }

     public   static   void  main ( String []  args )   {
         DigitalTimer  dt  =   new   DigitalTimer ();

         JPanel  p  =   new   JPanel ( new   FlowLayout ());
        p . add ( dt );

         JFrame  f  =   new   JFrame ( "DigitalTimer Demo" );
        f . setContentPane ( p );
        f . setSize ( 250 ,   100 );
        f . setVisible ( true );
     }
}

source/chapter09/InvokeAndWaitDemo.java

source/chapter09/InvokeAndWaitDemo.java

import  java . awt . * ;
import  java . awt . event . * ;
import  java . lang . reflect . * ;
import  javax . swing . * ;

public   class   InvokeAndWaitDemo   extends   Object   {
     private   static   void  print ( String  msg )   {
         String  name  =   Thread . currentThread (). getName ();
         System . out . println ( name  +   ": "   +  msg );
     }

     public   static   void  main ( String []  args )   {
         final   JLabel  label  =   new   JLabel ( "--------" );

         JPanel  panel  =   new   JPanel ( new   FlowLayout ());
        panel . add ( label );

         JFrame  f  =   new   JFrame ( "InvokeAndWaitDemo" );
        f . setContentPane ( panel );
        f . setSize ( 300 ,   100 );
        f . setVisible ( true );

         try   {
            print ( "sleeping for 3 seconds" );
             Thread . sleep ( 3000 );

            print ( "creating code block for event thread" );
             Runnable  setTextRun  =   new   Runnable ()   {
                     public   void  run ()   {
                        print ( "about to do setText()" );
                        label . setText ( "New text!" );
                     }
                 };
            
            print ( "about to invokeAndWait()" );
             SwingUtilities . invokeAndWait ( setTextRun );
            print ( "back from invokeAndWait()" );
         }   catch   (   InterruptedException  ix  )   {
            print ( "interrupted while waiting on invokeAndWait()" );
         }   catch   (   InvocationTargetException  x  )   {
            print ( "exception thrown from run()" );
         }
     }
}

source/chapter09/InvokeLaterDemo.java

source/chapter09/InvokeLaterDemo.java

import  java . awt . * ;
import  java . awt . event . * ;
import  javax . swing . * ;

public   class   InvokeLaterDemo   extends   Object   {
     private   static   void  print ( String  msg )   {
         String  name  =   Thread . currentThread (). getName ();
         System . out . println ( name  +   ": "   +  msg );
     }

     public   static   void  main ( String []  args )   {
         final   JLabel  label  =   new   JLabel ( "--------" );

         JPanel  panel  =   new   JPanel ( new   FlowLayout ());
        panel . add ( label );

         JFrame  f  =   new   JFrame ( "InvokeLaterDemo" );
        f . setContentPane ( panel );
        f . setSize ( 300 ,   100 );
        f . setVisible ( true );

         try   {
            print ( "sleeping for 3 seconds" );
             Thread . sleep ( 3000 );
         }   catch   (   InterruptedException  ix  )   {
            print ( "interrupted while sleeping" );
         }

        print ( "creating code block for event thread" );
         Runnable  setTextRun  =   new   Runnable ()   {
                 public   void  run ()   {
                     try   {
                         Thread . sleep ( 100 );   // for emphasis
                        print ( "about to do setText()" );
                        label . setText ( "New text!" );
                     }   catch   (   Exception  x  )   {
                        x . printStackTrace ();
                     }
                 }
             };
            
        print ( "about to invokeLater()" );
         SwingUtilities . invokeLater ( setTextRun );
        print ( "back from invokeLater()" );
     }
}

source/chapter09/ScrollText.java

source/chapter09/ScrollText.java

import  java . awt . * ;
import  java . awt . image . * ;
import  java . awt . font . * ;
import  java . awt . geom . * ;
import  javax . swing . * ;

public   class   ScrollText   extends   JComponent   {
     private   BufferedImage  image ;
     private   Dimension  imageSize ;
     private   volatile   int  currOffset ;

     private   Thread  internalThread ;
     private   volatile   boolean  noStopRequested ;

     public   ScrollText ( String  text )   {
        currOffset  =   0 ;
        buildImage ( text );

        setMinimumSize ( imageSize );
        setPreferredSize ( imageSize );
        setMaximumSize ( imageSize );
        setSize ( imageSize );

        noStopRequested  =   true ;
         Runnable  r  =   new   Runnable ()   {
                 public   void  run ()   {
                     try   {
                        runWork ();
                     }   catch   (   Exception  x  )   {
                        x . printStackTrace ();  
                     }
                 }
             };

        internalThread  =   new   Thread ( r ,   "ScrollText" );
        internalThread . start ();
     }

     private   void  buildImage ( String  text )   {
         // Request that the drawing be done with anti-aliasing
         // turned on and the quality high.
         RenderingHints  renderHints  =   new   RenderingHints (
             RenderingHints . KEY_ANTIALIASING ,
             RenderingHints . VALUE_ANTIALIAS_ON );

        renderHints . put (
             RenderingHints . KEY_RENDERING ,
             RenderingHints . VALUE_RENDER_QUALITY );

         // Create a scratch image for use in determining
         // the text dimensions.
         BufferedImage  scratchImage  =   new   BufferedImage (
                 1 ,   1 ,   BufferedImage . TYPE_INT_RGB );

         Graphics2D  scratchG2  =  scratchImage . createGraphics ();
        scratchG2 . setRenderingHints ( renderHints );

         Font  font  =  
             new   Font ( "Serif" ,   Font . BOLD  |   Font . ITALIC ,   24 );

         FontRenderContext  frc  =  scratchG2 . getFontRenderContext ();
         TextLayout  tl  =   new   TextLayout ( text ,  font ,  frc );
         Rectangle2D  textBounds  =  tl . getBounds ();
         int  textWidth  =   ( int )   Math . ceil ( textBounds . getWidth ());
         int  textHeight  =   ( int )   Math . ceil ( textBounds . getHeight ());

         int  horizontalPad  =   10 ;
         int  verticalPad  =   6 ;

        imageSize  =   new   Dimension (
                textWidth  +  horizontalPad ,
                textHeight  +  verticalPad
             );

         // Create the properly-sized image
        image  =   new   BufferedImage (
                imageSize . width ,
                imageSize . height ,
                 BufferedImage . TYPE_INT_RGB );

         Graphics2D  g2  =  image . createGraphics ();
        g2 . setRenderingHints ( renderHints );

         int  baselineOffset  =  
             (  verticalPad  /   2   )   -   (   ( int )  textBounds . getY ());

        g2 . setColor ( Color . white );
        g2 . fillRect ( 0 ,   0 ,  imageSize . width ,  imageSize . height );

        g2 . setColor ( Color . blue );
        tl . draw ( g2 ,   0 ,  baselineOffset );

         // Free-up resources right away, but keep "image" for
         // animation.
        scratchG2 . dispose ();
        scratchImage . flush ();
        g2 . dispose ();
     }

     public   void  paint ( Graphics  g )   {
         // Make sure to clip the edges, regardless of curr size
        g . setClip ( 0 ,   0 ,  imageSize . width ,  imageSize . height );

         int  localOffset  =  currOffset ;   // in case it changes
        g . drawImage ( image ,   - localOffset ,   0 ,   this );
        g . drawImage (
            image ,  imageSize . width  -  localOffset ,   0 ,   this );

         // draw outline
        g . setColor ( Color . black );
        g . drawRect (
             0 ,   0 ,  imageSize . width  -   1 ,  imageSize . height  -   1 );
     }

     private   void  runWork ()   {
         while   (  noStopRequested  )   {
             try   {
                 Thread . sleep ( 100 );    // 10 frames per second
                
                 // adjust the scroll position
                currOffset  =  
                     (  currOffset  +   1   )   %  imageSize . width ;

                 // signal the event thread to call paint()
                repaint ();
             }   catch   (   InterruptedException  x  )   {
                 Thread . currentThread (). interrupt ();  
             }
         }
     }

     public   void  stopRequest ()   {
        noStopRequested  =   false ;
        internalThread . interrupt ();
     }

     public   boolean  isAlive ()   {
         return  internalThread . isAlive ();
     }

     public   static   void  main ( String []  args )   {
         ScrollText  st  =  
             new   ScrollText ( "Java can do animation!" );

         JPanel  p  =   new   JPanel ( new   FlowLayout ());
        p . add ( st );

         JFrame  f  =   new   JFrame ( "ScrollText Demo" );
        f . setContentPane ( p );
        f . setSize ( 400 ,   100 );
        f . setVisible ( true );
     }
}

source/chapter09/SimpleEvent.java

source/chapter09/SimpleEvent.java

import  java . awt . * ;
import  java . awt . event . * ;
import  javax . swing . * ;

public   class   SimpleEvent   extends   Object   {
     private   static   void  print ( String  msg )   {
         String  name  =   Thread . currentThread (). getName ();
         System . out . println ( name  +   ": "   +  msg );
     }

     public   static   void  main ( String []  args )   {
         final   JLabel  label  =   new   JLabel ( "--------" );
         JButton  button  =   new   JButton ( "Click Here" );

         JPanel  panel  =   new   JPanel ( new   FlowLayout ());
        panel . add ( button );
        panel . add ( label );

        button . addActionListener ( new   ActionListener ()   {
                 public   void  actionPerformed ( ActionEvent  e )   {
                    print ( "in actionPerformed()" );
                    label . setText ( "CLICKED!" );
                 }
             });

         JFrame  f  =   new   JFrame ( "SimpleEvent" );
        f . setContentPane ( panel );
        f . setSize ( 300 ,   100 );
        f . setVisible ( true );
     }
}

source/chapter09/SlideShow.java

source/chapter09/SlideShow.java

import  java . awt . * ;
import  java . awt . image . * ;
import  javax . swing . * ;

public   class   SlideShow   extends   JComponent   {
     private   BufferedImage []  slide ;
     private   Dimension  slideSize ;
     private   volatile   int  currSlide ;

     private   Thread  internalThread ;
     private   volatile   boolean  noStopRequested ;

     public   SlideShow ()   {
        currSlide  =   0 ;
        slideSize  =   new   Dimension ( 50 ,   50 );
        buildSlides ();

        setMinimumSize ( slideSize );
        setPreferredSize ( slideSize );
        setMaximumSize ( slideSize );
        setSize ( slideSize );

        noStopRequested  =   true ;
         Runnable  r  =   new   Runnable ()   {
                 public   void  run ()   {
                     try   {
                        runWork ();
                     }   catch   (   Exception  x  )   {
                         // in case ANY exception slips through
                        x . printStackTrace ();  
                     }
                 }
             };

        internalThread  =   new   Thread ( r ,   "SlideShow" );
        internalThread . start ();
     }

     private   void  buildSlides ()   {
         // Request that the drawing be done with anti-aliasing
         // turned on and the quality high.
         RenderingHints  renderHints  =   new   RenderingHints (
             RenderingHints . KEY_ANTIALIASING ,
             RenderingHints . VALUE_ANTIALIAS_ON );

        renderHints . put (
             RenderingHints . KEY_RENDERING ,
             RenderingHints . VALUE_RENDER_QUALITY );

        slide  =   new   BufferedImage [ 20 ];

         Color  rectColor  =   new   Color ( 100 ,   160 ,   250 );     // blue
         Color  circleColor  =   new   Color ( 250 ,   250 ,   150 );   // yellow

         for   (   int  i  =   0 ;  i  <  slide . length ;  i ++   )   {
            slide [ i ]   =   new   BufferedImage (
                    slideSize . width ,
                    slideSize . height ,
                     BufferedImage . TYPE_INT_RGB );

             Graphics2D  g2  =  slide [ i ]. createGraphics ();
            g2 . setRenderingHints ( renderHints );

            g2 . setColor ( rectColor );
            g2 . fillRect ( 0 ,   0 ,  slideSize . width ,  slideSize . height );

            g2 . setColor ( circleColor );

             int  diameter  =   0 ;
             if   (  i  <   (  slide . length  /   2   )   )   {
                diameter  =   5   +   (   8   *  i  );
             }   else   {
                diameter  =   5   +   (   8   *    (  slide . length  -  i  )   );
             }

             int  inset  =   (  slideSize . width  -  diameter  )   /   2 ;
            g2 . fillOval ( inset ,  inset ,  diameter ,  diameter );

            g2 . setColor ( Color . black );
            g2 . drawRect (
                 0 ,   0 ,  slideSize . width  -   1 ,  slideSize . height  -   1 );

            g2 . dispose ();
         }
     }

     public   void  paint ( Graphics  g )   {
        g . drawImage ( slide [ currSlide ],   0 ,   0 ,   this );
     }

     private   void  runWork ()   {
         while   (  noStopRequested  )   {
             try   {
                 Thread . sleep ( 100 );    // 10 frames per second
                
                 // increment the slide pointer
                currSlide  =   (  currSlide  +   1   )   %  slide . length ;

                 // signal the event thread to call paint()
                repaint ();
             }   catch   (   InterruptedException  x  )   {
                 Thread . currentThread (). interrupt ();  
             }
         }
     }

     public   void  stopRequest ()   {
        noStopRequested  =   false ;
        internalThread . interrupt ();
     }

     public   boolean  isAlive ()   {
         return  internalThread . isAlive ();
     }

     public   static   void  main ( String []  args )   {
         SlideShow  ss  =   new   SlideShow ();

         JPanel  p  =   new   JPanel ( new   FlowLayout ());
        p . add ( ss );

         JFrame  f  =   new   JFrame ( "SlideShow Demo" );
        f . setContentPane ( p );
        f . setSize ( 250 ,   150 );
        f . setVisible ( true );
     }
}

source/chapter10/ThreadViewer.java

source/chapter10/ThreadViewer.java

import  java . awt . * ;
import  java . awt . event . * ;
import  javax . swing . * ;
import  javax . swing . table . * ;

public   class   ThreadViewer   extends   JPanel   {
     private   ThreadViewerTableModel  tableModel ;

     public   ThreadViewer ()   {
        tableModel  =   new   ThreadViewerTableModel ();

         JTable  table  =   new   JTable ( tableModel );
        table . setAutoResizeMode ( JTable . AUTO_RESIZE_LAST_COLUMN );

         TableColumnModel  colModel  =  table . getColumnModel ();
         int  numColumns  =  colModel . getColumnCount ();

         // manually size all but the last column
         for   (   int  i  =   0 ;  i  <  numColumns  -   1 ;  i ++   )   {
             TableColumn  col  =  colModel . getColumn ( i );

            col . sizeWidthToFit ();
            col . setPreferredWidth ( col . getWidth ()   +   5 );
            col . setMaxWidth ( col . getWidth ()   +   5 );
         }

         JScrollPane  sp  =   new   JScrollPane ( table );

        setLayout ( new   BorderLayout ());
        add ( sp ,   BorderLayout . CENTER );
     }

     public   void  dispose ()   {
        tableModel . stopRequest ();
     }

     protected   void  finalize ()   throws   Throwable   {
        dispose ();
     }

     public   static   JFrame  createFramedInstance ()   {
         final   ThreadViewer  viewer  =   new   ThreadViewer ();

         final   JFrame  f  =   new   JFrame ( "ThreadViewer" );
        f . addWindowListener ( new   WindowAdapter ()   {
                 public   void  windowClosing ( WindowEvent  e )   {
                    f . setVisible ( false );
                    f . dispose ();
                    viewer . dispose ();
                 }
             });

        f . setContentPane ( viewer );
        f . setSize ( 500 ,   300 );
        f . setVisible ( true );

         return  f ;
     }
    
     public   static   void  main ( String []  args )   {
         JFrame  f  =   ThreadViewer . createFramedInstance ();

         // For this example, exit the VM when the viewer
         // frame is closed.
        f . addWindowListener ( new   WindowAdapter ()   {
                 public   void  windowClosing ( WindowEvent  e )   {
                     System . exit ( 0 );
                 }
             });

         // Keep the main thread from exiting by blocking
         // on wait() for a notification that never comes.
         Object  lock  =   new   Object ();
         synchronized   (  lock  )   {
             try   {
                lock . wait ();
             }   catch   (   InterruptedException  x  )   {
             }
         }
     }
}

source/chapter10/ThreadViewerTableModel.java

source/chapter10/ThreadViewerTableModel.java

import  java . awt . * ;
import  java . lang . reflect . * ;
import  javax . swing . * ;
import  javax . swing . table . * ;

public   class   ThreadViewerTableModel   extends   AbstractTableModel   {
     private   Object  dataLock ;  
     private   int  rowCount ;
     private   Object [][]  cellData ;
     private   Object [][]  pendingCellData ;

     // the column information remains constant
     private   final   int  columnCount ;
     private   final   String []  columnName ;
     private   final   Class []  columnClass ;

     // self-running object control variables
     private   Thread  internalThread ;
     private   volatile   boolean  noStopRequested ;

     public   ThreadViewerTableModel ()   {
        rowCount  =   0 ;
        cellData  =   new   Object [ 0 ][ 0 ];

         // JTable uses this information for the column headers
         String []  names  =   {  
             "Priority" ,   "Alive" ,  
             "Daemon" ,   "Interrupted" ,  
             "ThreadGroup" ,   "Thread Name"   };
        columnName  =  names ;                          
                        
         // JTable uses this information for cell rendering
         Class []  classes  =   {  
             Integer . class ,   Boolean . class ,  
             Boolean . class ,   Boolean . class ,  
             String . class ,   String . class   };
        columnClass  =  classes ;

        columnCount  =  columnName . length ;

         // used to control concurrent access
        dataLock  =   new   Object ();  

        noStopRequested  =   true ;
         Runnable  r  =   new   Runnable ()   {
                 public   void  run ()   {
                     try   {
                        runWork ();
                     }   catch   (   Exception  x  )   {
                         // in case ANY exception slips through
                        x . printStackTrace ();  
                     }
                 }
             };

        internalThread  =   new   Thread ( r ,   "ThreadViewer" );
        internalThread . setPriority ( Thread . MAX_PRIORITY  -   2 );
        internalThread . setDaemon ( true );
        internalThread . start ();
     }

     private   void  runWork ()   {

         // The run() method of transferPending is called by 
         // the event handling thread for safe concurrency.
         Runnable  transferPending  =   new   Runnable ()   {
                 public   void  run ()   {
                    transferPendingCellData ();

                     // Method of AbstractTableModel that 
                     // causes the table to be updated.
                    fireTableDataChanged ();  
                 }
             };

         while   (  noStopRequested  )   {
             try   {
                createPendingCellData ();
                 SwingUtilities . invokeAndWait ( transferPending );
                 Thread . sleep ( 5000 );
             }   catch   (   InvocationTargetException  tx  )   {
                tx . printStackTrace ();
                stopRequest ();
             }   catch   (   InterruptedException  x  )   {
                 Thread . currentThread (). interrupt ();  
             }
         }
     }

     public   void  stopRequest ()   {
        noStopRequested  =   false ;
        internalThread . interrupt ();
     }

     public   boolean  isAlive ()   {
         return  internalThread . isAlive ();
     }

     private   void  createPendingCellData ()   {
         // this method is called by the internal thread
         Thread []  thread  =  findAllThreads ();
         Object [][]  cell  =   new   Object [ thread . length ][ columnCount ];

         for   (   int  i  =   0 ;  i  <  thread . length ;  i ++   )   {
             Thread  t  =  thread [ i ];
             Object []  rowCell  =  cell [ i ];

            rowCell [ 0 ]   =   new   Integer ( t . getPriority ());
            rowCell [ 1 ]   =   new   Boolean ( t . isAlive ());
            rowCell [ 2 ]   =   new   Boolean ( t . isDaemon ());
            rowCell [ 3 ]   =   new   Boolean ( t . isInterrupted ());
            rowCell [ 4 ]   =  t . getThreadGroup (). getName ();
            rowCell [ 5 ]   =  t . getName ();
         }

         synchronized   (  dataLock  )   {
            pendingCellData  =  cell ;
         }
     }

     private   void  transferPendingCellData ()   {
         // this method is called by the event thread
         synchronized   (  dataLock  )   {
            cellData  =  pendingCellData ;
            rowCount  =  cellData . length ;
         }
     }

     public   int  getRowCount ()   {
         // this method is called by the event thread
         return  rowCount ;
     }
    
     public   Object  getValueAt ( int  row ,   int  col )   {
         // this method is called by the event thread
         return  cellData [ row ][ col ];
     }

     public   int  getColumnCount ()   {
         return  columnCount ;
     }

     public   Class  getColumnClass ( int  columnIdx )   {
         return  columnClass [ columnIdx ];
     }

     public   String  getColumnName ( int  columnIdx )   {
         return  columnName [ columnIdx ];
     }

     public   static   Thread []  findAllThreads ()   {
         ThreadGroup  group  =  
             Thread . currentThread (). getThreadGroup ();

         ThreadGroup  topGroup  =  group ;

         // traverse the ThreadGroup tree to the top
         while   (  group  !=   null   )   {
            topGroup  =  group ;
            group  =  group . getParent ();
         }

         // Create a destination array that is about
         // twice as big as needed to be very confident
         // that none are clipped.
         int  estimatedSize  =  topGroup . activeCount ()   *   2 ;
         Thread []  slackList  =   new   Thread [ estimatedSize ];

         // Load the thread references into the oversized
         // array. The actual number of threads loaded 
         // is returned.
         int  actualSize  =  topGroup . enumerate ( slackList );

         // copy into a list that is the exact size
         Thread []  list  =   new   Thread [ actualSize ];
         System . arraycopy ( slackList ,   0 ,  list ,   0 ,  actualSize );

         return  list ;
     }
}

source/chapter11/InnerSelfRun.java

source/chapter11/InnerSelfRun.java

public   class   InnerSelfRun   extends   Object   {
     private   Thread  internalThread ;
     private   volatile   boolean  noStopRequested ;

     public   InnerSelfRun ()   {
         // other constructor stuff should appear here first ...
         System . out . println ( "in constructor - initializing..." );

         // just before returning, the thread should be created and started.
        noStopRequested  =   true ;

         Runnable  r  =   new   Runnable ()   {
                 public   void  run ()   {
                     try   {
                        runWork ();
                     }   catch   (   Exception  x  )   {
                         // in case ANY exception slips through
                        x . printStackTrace ();  
                     }
                 }
             };

        internalThread  =   new   Thread ( r );
        internalThread . start ();
     }

     private   void  runWork ()   {
         while   (  noStopRequested  )   {
             System . out . println ( "in runWork() - still going..." );

             try   {
                 Thread . sleep ( 700 );
             }   catch   (   InterruptedException  x  )   {
                 // Any caught interrupts should be habitually re-asserted
                 // for any blocking statements which follow.
                 Thread . currentThread (). interrupt ();   // re-assert interrupt
             }
         }
     }

     public   void  stopRequest ()   {
        noStopRequested  =   false ;
        internalThread . interrupt ();
     }

     public   boolean  isAlive ()   {
         return  internalThread . isAlive ();
     }
}

source/chapter11/InnerSelfRunMain.java

source/chapter11/InnerSelfRunMain.java

public   class   InnerSelfRunMain   extends   Object   {
     public   static   void  main ( String []  args )   {
         InnerSelfRun  sr  =   new   InnerSelfRun ();

         try   {   Thread . sleep ( 3000 );   }   catch   (   InterruptedException  x  )   {   }

        sr . stopRequest ();
     }
}

source/chapter11/SelfRun.java

source/chapter11/SelfRun.java

public   class   SelfRun   extends   Object   implements   Runnable   {
     private   Thread  internalThread ;
     private   volatile   boolean  noStopRequested ;

     public   SelfRun ()   {
         // other constructor stuff should appear here first ...
         System . out . println ( "in constructor - initializing..." );

         // Just before returning, the thread should be 
         // created and started.
        noStopRequested  =   true ;
        internalThread  =   new   Thread ( this );
        internalThread . start ();
     }

     public   void  run ()   {
         // Check that no one has erroneously invoked 
         // this public method.
         if   (   Thread . currentThread ()   !=  internalThread  )   {
             throw   new   RuntimeException ( "only the internal "   +
                 "thread is allowed to invoke run()" );
         }

         while   (  noStopRequested  )   {
             System . out . println ( "in run() - still going..." );

             try   {
                 Thread . sleep ( 700 );
             }   catch   (   InterruptedException  x  )   {
                 // Any caught interrupts should be habitually 
                 // reasserted for any blocking statements 
                 // which follow.
                 Thread . currentThread (). interrupt ();  
             }
         }
     }

     public   void  stopRequest ()   {
        noStopRequested  =   false ;
        internalThread . interrupt ();
     }

     public   boolean  isAlive ()   {
         return  internalThread . isAlive ();
     }
}

source/chapter11/SelfRunMain.java

source/chapter11/SelfRunMain.java

public   class   SelfRunMain   extends   Object   {
     public   static   void  main ( String []  args )   {
         SelfRun  sr  =   new   SelfRun ();

         try   {   Thread . sleep ( 3000 );   }   catch   (   InterruptedException  x  )   {   }

        sr . stopRequest ();
     }
}

source/chapter11/Squish.java

source/chapter11/Squish.java

import  java . awt . * ;
import  java . awt . image . * ;
import  java . awt . geom . * ;
import  javax . swing . * ;

public   class   Squish   extends   JComponent   {
     private   Image []  frameList ;
     private   long  msPerFrame ;
     private   volatile   int  currFrame ;

     private   Thread  internalThread ;
     private   volatile   boolean  noStopRequested ;

     public   Squish (
                 int  width ,
                 int  height ,
                 long  msPerCycle ,  
                 int  framesPerSec ,  
                 Color  fgColor
             )   {

        setPreferredSize ( new   Dimension ( width ,  height ));

         int  framesPerCycle  =  
                 ( int )   (   (  framesPerSec  *  msPerCycle  )   /   1000   );
        msPerFrame  =   1000L   /  framesPerSec ;

        frameList  =  
            buildImages ( width ,  height ,  fgColor ,  framesPerCycle );
        currFrame  =   0 ;

        noStopRequested  =   true ;
         Runnable  r  =   new   Runnable ()   {
                 public   void  run ()   {
                     try   {
                        runWork ();
                     }   catch   (   Exception  x  )   {
                         // in case ANY exception slips through
                        x . printStackTrace ();  
                     }
                 }
             };

        internalThread  =   new   Thread ( r );
        internalThread . start ();
     }

     private   Image []  buildImages (
                 int  width ,  
                 int  height ,  
                 Color  color ,
                 int  count
             )   {

         BufferedImage []  im  =   new   BufferedImage [ count ];

         for   (   int  i  =   0 ;  i  <  count ;  i ++   )   {
            im [ i ]   =   new   BufferedImage (
                    width ,  height ,   BufferedImage . TYPE_INT_ARGB );

             double  xShape  =   0.0 ;
             double  yShape  =  
                 (   ( double )   (  i  *  height  )   )   /   ( double )  count ;

             double  wShape  =  width ;
             double  hShape  =   2.0   *   (  height  -  yShape  );
             Ellipse2D  shape  =   new   Ellipse2D . Double (
                        xShape ,  yShape ,  wShape ,  hShape );

             Graphics2D  g2  =  im [ i ]. createGraphics ();
            g2 . setColor ( color );
            g2 . fill ( shape );
            g2 . dispose ();
         }

         return  im ;
     }

     private   void  runWork ()   {
         while   (  noStopRequested  )   {
            currFrame  =   (  currFrame  +   1   )   %  frameList . length ;
            repaint ();

             try   {
                 Thread . sleep ( msPerFrame );
             }   catch   (   InterruptedException  x  )   {
                 // reassert interrupt
                 Thread . currentThread (). interrupt ();  
                 // continue on as if sleep completed normally
             }
         }
     }

     public   void  stopRequest ()   {
        noStopRequested  =   false ;
        internalThread . interrupt ();
     }

     public   boolean  isAlive ()   {
         return  internalThread . isAlive ();
     }

     public   void  paint ( Graphics  g )   {
        g . drawImage ( frameList [ currFrame ],   0 ,   0 ,   this );
     }
}

source/chapter11/SquishMain.java

source/chapter11/SquishMain.java

import  java . awt . * ;
import  java . awt . event . * ;
import  javax . swing . * ;

public   class   SquishMain   extends   JPanel   {
     public   SquishMain ()   {
         Squish  blueSquish  =   new   Squish ( 150 ,   150 ,   3000L ,   10 ,   Color . blue );
         Squish  redSquish  =   new   Squish ( 250 ,   200 ,   2500L ,   10 ,   Color . red );

         this . setLayout ( new   FlowLayout ());
         this . add ( blueSquish );
         this . add ( redSquish );
     }

     public   static   void  main ( String []  args )   {
         SquishMain  sm  =   new   SquishMain ();

         JFrame  f  =   new   JFrame ( "Squish Main" );
        f . setContentPane ( sm );
        f . setSize ( 450 ,   250 );
        f . setVisible ( true );
        f . addWindowListener ( new   WindowAdapter ()   {
                 public   void  windowClosing ( WindowEvent  e )   {
                     System . exit ( 0 );
                 }
             });
     }
}

source/chapter12/ExceptionCallback.java

source/chapter12/ExceptionCallback.java

import  java . io . * ;
import  java . util . * ;

public   class   ExceptionCallback   extends   Object   {
     private   Set  exceptionListeners ;
     private   Thread  internalThread ;
     private   volatile   boolean  noStopRequested ;

     public   ExceptionCallback ( ExceptionListener []  initialGroup )   {
        init ( initialGroup );
     }

     public   ExceptionCallback ( ExceptionListener  initialListener )   {
         ExceptionListener []  group  =   new   ExceptionListener [ 1 ];
        group [ 0 ]   =  initialListener ;
        init ( group );
     }

     public   ExceptionCallback ()   {
        init ( null );
     }

     private   void  init ( ExceptionListener []  initialGroup )   {
         System . out . println ( "in constructor - initializing..." );

        exceptionListeners  =  
                 Collections . synchronizedSet ( new   HashSet ());

         // If any listeners should be added before the internal
         // thread starts, add them now.
         if   (  initialGroup  !=   null   )   {
             for   (   int  i  =   0 ;  i  <  initialGroup . length ;  i ++   )   {
                addExceptionListener ( initialGroup [ i ]);
             }
         }

         // Just before returning from the constructor, 
         // the thread should be created and started.
        noStopRequested  =   true ;

         Runnable  r  =   new   Runnable ()   {
                 public   void  run ()   {
                     try   {
                        runWork ();
                     }   catch   (   Exception  x  )   {
                         // in case ANY exception slips through
                        sendException ( x );
                     }
                 }
             };

        internalThread  =   new   Thread ( r );
        internalThread . start ();
     }

     private   void  runWork ()   {
         try   {
            makeConnection ();   // will throw an IOException
         }   catch   (   IOException  x  )   {
            sendException ( x );
             // Probably in a real scenario, a "return" 
             // statement should be here.
         }  

         String  str  =   null ;
         int  len  =  determineLength ( str );   // NullPointerException
     }

     private   void  makeConnection ()   throws   IOException   {
         // A NumberFormatException will be thrown when
         // this String is parsed.
         String  portStr  =   "j20" ;  
         int  port  =   0 ;

         try   {
            port  =   Integer . parseInt ( portStr );
         }   catch   (   NumberFormatException  x  )   {
            sendException ( x );
            port  =   80 ;   // use default;
         }  

        connectToPort ( port );   // will throw an IOException
     }

     private   void  connectToPort ( int  portNum )   throws   IOException   {
         throw   new   IOException ( "connection refused" );
     }

     private   int  determineLength ( String  s )   {
         return  s . length ();
     }

     public   void  stopRequest ()   {
        noStopRequested  =   false ;
        internalThread . interrupt ();
     }

     public   boolean  isAlive ()   {
         return  internalThread . isAlive ();
     }

     private   void  sendException ( Exception  x )   {
         if   (  exceptionListeners . size ()   ==   0   )   {
             // If there aren't any listeners, dump the stack
             // trace to the console.
            x . printStackTrace ();
             return ;
         }

         // Used "synchronized" to make sure that other threads
         // do not make changes to the Set while iterating.
         synchronized   (  exceptionListeners  )   {
             Iterator  iter  =  exceptionListeners . iterator ();
             while   (  iter . hasNext ()   )   {
                 ExceptionListener  l  =  
                         ( ExceptionListener )  iter . next ();

                l . exceptionOccurred ( x ,   this );
             }
         }
     }

     public   void  addExceptionListener ( ExceptionListener  l )   {
         // Silently ignore a request to add a "null" listener.
         if   (  l  !=   null   )   {
             // If a listener was already in the Set, it will
             // silently replace itself so that no duplicates
             // accumulate.
            exceptionListeners . add ( l );
         }
     }

     public   void  removeExceptionListener ( ExceptionListener  l )   {
         // Silently ignore a request to remove a listener
         // that is not in the Set.
        exceptionListeners . remove ( l );
     }

     public   String  toString ()   {
         return  getClass (). getName ()   +  
             "[isAlive()="   +  isAlive ()   +   "]" ;
     }
}

source/chapter12/ExceptionCallbackMain.java

source/chapter12/ExceptionCallbackMain.java

public   class   ExceptionCallbackMain  
         extends   Object  
         implements   ExceptionListener   {

     private   int  exceptionCount ;

     public   ExceptionCallbackMain ()   {
        exceptionCount  =   0 ;
     }

     public   void  exceptionOccurred ( Exception  x ,   Object  source )   {
        exceptionCount ++ ;
         System . err . println ( "EXCEPTION #"   +  exceptionCount  +
                 ", source="   +  source );
        x . printStackTrace ();
     }

     public   static   void  main ( String []  args )   {
         ExceptionListener  xListener  =   new   ExceptionCallbackMain ();
         ExceptionCallback  ec  =   new   ExceptionCallback ( xListener );
     }
}

source/chapter12/ExceptionListener.java

source/chapter12/ExceptionListener.java

public   interface   ExceptionListener   {
     public   void  exceptionOccurred ( Exception  x ,   Object  source );
}

source/chapter13/htmldir/images/five.gif

source/chapter13/htmldir/images/four.gif

source/chapter13/htmldir/images/one.gif

source/chapter13/htmldir/images/three.gif

source/chapter13/htmldir/images/two.gif

source/chapter13/htmldir/index.html

Thread pooling helps to save the VM the work of creating anddestroying threads when they can be easily recycled.
Thread pooling reduces response time since the worker threadis already created, started, and running. It is only waitingfor the signal to go!
Thread pooling holds resource usage to a predetermined, upperlimit. Instead of starting a new thread for every requestreceived by an HTTP server, a set of workers is available to service requests. When this set is being completely used by other requests, the server does not increase its load, but rejects requests until a worker becomes available.
Thread pooling generally works best when a thread is onlyneeded for a brief period of time.
When using the thread pooling technique, care must be takento reasonably ensure that threads don't become deadlocked ordie.

source/chapter13/HttpServer.java

source/chapter13/HttpServer.java

import  java . io . * ;
import  java . net . * ;

// uses ObjectFIFO from chapter 18

public   class   HttpServer   extends   Object   {

     // currently available HttpWorker objects
     private   ObjectFIFO  idleWorkers ;

     // all HttpWorker objects
     private   HttpWorker []  workerList ;
     private   ServerSocket  ss ;

     private   Thread  internalThread ;
     private   volatile   boolean  noStopRequested ;

     public   HttpServer (
                 File  docRoot ,
                 int  port ,
                 int  numberOfWorkers ,
                 int  maxPriority
             )   throws   IOException   {

         // Allow a max of 10 sockets to queue up 
         // waiting for accpet().
        ss  =   new   ServerSocket ( port ,   10 );  

         if   (   (  docRoot  ==   null   )   ||  
              ! docRoot . exists ()   ||  
              ! docRoot . isDirectory ()  
            )   {

             throw   new   IOException ( "specified docRoot is null "   +
                 "or does not exist or is not a directory" );
         }

         // ensure that at least one worker is created
        numberOfWorkers  =   Math . max ( 1 ,  numberOfWorkers );

         // Ensure: 
         // (minAllowed + 2) <= serverPriority <= (maxAllowed - 1)
         // which is generally:
         //   3 <= serverPriority <= 9
         int  serverPriority  =   Math . max (
                 Thread . MIN_PRIORITY  +   2 ,  
                 Math . min ( maxPriority ,   Thread . MAX_PRIORITY  -   1 )
             );

         // Have the workers run at a slightly lower priority so 
         // that new requests are handled with more urgency than 
         // in-progress requests.
         int  workerPriority  =  serverPriority  -   1 ;

        idleWorkers  =   new   ObjectFIFO ( numberOfWorkers );
        workerList  =   new   HttpWorker [ numberOfWorkers ];

         for   (   int  i  =   0 ;  i  <  numberOfWorkers ;  i ++   )   {
             // Workers get a reference to the FIFO to add 
             // themselves back in when they are ready to 
             // handle a new request.
            workerList [ i ]   =   new   HttpWorker (
                        docRoot ,  workerPriority ,  idleWorkers );
         }

         // Just before returning, the thread should be 
         // created and started.
        noStopRequested  =   true ;

         Runnable  r  =   new   Runnable ()   {
                 public   void  run ()   {
                     try   {
                        runWork ();
                     }   catch   (   Exception  x  )   {
                         // in case ANY exception slips through
                        x . printStackTrace ();  
                     }
                 }
             };

        internalThread  =   new   Thread ( r );
        internalThread . setPriority ( serverPriority );  
        internalThread . start ();
     }

     private   void  runWork ()   {
         System . out . println (
                 "HttpServer ready to receive requests" );

         while   (  noStopRequested  )   {
             try   {
                 Socket  s  =  ss . accept ();

                 if   (  idleWorkers . isEmpty ()   )   {
                     System . out . println (
                         "HttpServer too busy, denying request" );

                     BufferedWriter  writer  =  
                         new   BufferedWriter (
                             new   OutputStreamWriter (
                                s . getOutputStream ()));
                    
                    writer . write ( "HTTP/1.0 503 Service "   +
                                     "Unavailable\r\n\r\n" );

                    writer . flush ();
                    writer . close ();
                    writer  =   null ;
                 }   else   {
                     // No need to be worried that idleWorkers 
                     // will suddenly be empty since this is the 
                     // only thread removing items from the queue.
                     HttpWorker  worker  =  
                             ( HttpWorker )  idleWorkers . remove ();

                    worker . processRequest ( s );
                 }
             }   catch   (   IOException  iox  )   {
                 if   (  noStopRequested  )   {
                    iox . printStackTrace ();
                 }
             }   catch   (   InterruptedException  x  )   {
                 // re-assert interrupt
                 Thread . currentThread (). interrupt ();  
             }
         }
     }

     public   void  stopRequest ()   {
        noStopRequested  =   false ;
        internalThread . interrupt ();

         for   (   int  i  =   0 ;  i  <  workerList . length ;  i ++   )   {
            workerList [ i ]. stopRequest ();
         }

         if   (  ss  !=   null   )   {
             try   {  ss . close ();   }   catch   (   IOException  iox  )   {   }
            ss  =   null ;
         }
     }

     public   boolean  isAlive ()   {
         return  internalThread . isAlive ();
     }

     private   static   void  usageAndExit ( String  msg ,   int  exitCode )   {
         System . err . println ( msg );
         System . err . println ( "Usage: java HttpServer <port> "   +
                             "<numWorkers> <documentRoot>" );
         System . err . println ( "   <port> - port to listen on "   +
                             "for HTTP requests" );
         System . err . println ( "   <numWorkers> - number of "   +
                             "worker threads to create" );
         System . err . println ( "   <documentRoot> - base "   +
                             "directory for HTML files" );
         System . exit ( exitCode );
     }

     public   static   void  main ( String []  args )   {
         if   (  args . length  !=   3   )   {
            usageAndExit ( "wrong number of arguments" ,   1 );
         }

         String  portStr  =  args [ 0 ];
         String  numWorkersStr  =  args [ 1 ];
         String  docRootStr  =  args [ 2 ];

         int  port  =   0 ;

         try   {
            port  =   Integer . parseInt ( portStr );
         }   catch   (   NumberFormatException  x  )   {
            usageAndExit ( "could not parse port number from '"   +  
                    portStr  +   "'" ,   2 );
         }

         if   (  port  <   1   )   {
            usageAndExit ( "invalid port number specified: "   +  
                    port ,   3 );
         }

         int  numWorkers  =   0 ;

         try   {
            numWorkers  =   Integer . parseInt ( numWorkersStr );
         }   catch   (   NumberFormatException  x  )   {
            usageAndExit (
                     "could not parse number of workers from '"   +  
                    numWorkersStr  +   "'" ,   4 );
         }

         File  docRoot  =   new   File ( docRootStr );

         try   {
             new   HttpServer ( docRoot ,  port ,  numWorkers ,   6 );
         }   catch   (   IOException  x  )   {
            x . printStackTrace ();
            usageAndExit ( "could not construct HttpServer" ,   5 );
         }
     }
}

source/chapter13/HttpWorker.java

source/chapter13/HttpWorker.java

import  java . io . * ;
import  java . net . * ;
import  java . util . * ;

// uses class ObjectFIFO from chapter 18

public   class   HttpWorker   extends   Object   {
     private   static   int  nextWorkerID  =   0 ;

     private   File  docRoot ;
     private   ObjectFIFO  idleWorkers ;
     private   int  workerID ;
     private   ObjectFIFO  handoffBox ;

     private   Thread  internalThread ;
     private   volatile   boolean  noStopRequested ;

     public   HttpWorker (
                 File  docRoot ,  
                 int  workerPriority ,  
                 ObjectFIFO  idleWorkers
             )   {

         this . docRoot  =  docRoot ;
         this . idleWorkers  =  idleWorkers ;

        workerID  =  getNextWorkerID ();
        handoffBox  =   new   ObjectFIFO ( 1 );   // only one slot

         // Just before returning, the thread should be 
         // created and started.
        noStopRequested  =   true ;

         Runnable  r  =   new   Runnable ()   {
                 public   void  run ()   {
                     try   {
                        runWork ();
                     }   catch   (   Exception  x  )   {
                         // in case ANY exception slips through
                        x . printStackTrace ();  
                     }
                 }
             };

        internalThread  =   new   Thread ( r );
        internalThread . setPriority ( workerPriority );
        internalThread . start ();
     }

     public   static   synchronized   int  getNextWorkerID ()   {  
         // synchronized at the class level to ensure uniqueness
         int  id  =  nextWorkerID ;
        nextWorkerID ++ ;
         return  id ;
     }

     public   void  processRequest ( Socket  s )  
                 throws   InterruptedException   {

        handoffBox . add ( s );
     }

     private   void  runWork ()   {
         Socket  s  =   null ;
         InputStream  in  =   null ;
         OutputStream  out  =   null ;

         while   (  noStopRequested  )   {
             try   {
                 // Worker is ready to receive new service 
                 // requests, so it adds itself to the idle 
                 // worker queue.
                idleWorkers . add ( this );

                 // Wait here until the server puts a request 
                 // into the handoff box.
                s  =   ( Socket )  handoffBox . remove ();

                in  =  s . getInputStream ();
                out  =  s . getOutputStream ();
                generateResponse ( in ,  out );
                out . flush ();
             }   catch   (   IOException  iox  )   {
                 System . err . println (
                     "I/O error while processing request, "   +
                     "ignoring and adding back to idle "   +
                     "queue - workerID="   +  workerID );
             }   catch   (   InterruptedException  x  )   {
                 // re-assert the interrupt
                 Thread . currentThread (). interrupt ();  
             }   finally   {
                 // Try to close everything, ignoring 
                 // any IOExceptions that might occur.
                 if   (  in  !=   null   )   {
                     try   {  
                        in . close ();  
                     }   catch   (   IOException  iox  )   {
                         // ignore
                     }   finally   {
                        in  =   null ;
                     }
                 }

                 if   (  out  !=   null   )   {
                     try   {  
                        out . close ();  
                     }   catch   (   IOException  iox  )   {
                         // ignore
                     }   finally   {
                        out  =   null ;
                     }
                 }

                 if   (  s  !=   null   )   {
                     try   {  
                        s . close ();  
                     }   catch   (   IOException  iox  )   {
                         // ignore
                     }   finally   {
                        s  =   null ;
                     }
                 }
             }
         }
     }

     private   void  generateResponse (
                 InputStream  in ,  
                 OutputStream  out
             )   throws   IOException   {

         BufferedReader  reader  =  
                 new   BufferedReader ( new   InputStreamReader ( in ));

         String  requestLine  =  reader . readLine ();

         if   (   (  requestLine  ==   null   )   ||  
              (  requestLine . length ()   <   1   )  
            )   {

             throw   new   IOException ( "could not read request" );
         }

         System . out . println ( "workerID="   +  workerID  +  
                 ", requestLine="   +  requestLine );

         StringTokenizer  st  =   new   StringTokenizer ( requestLine );
         String  filename  =   null ;

         try   {
             // request method, typically 'GET', but ignored
            st . nextToken ();  

             // the second token should be the filename
            filename  =  st . nextToken ();
         }   catch   (   NoSuchElementException  x  )   {
             throw   new   IOException (
                     "could not parse request line" );
         }

         File  requestedFile  =  generateFile ( filename );

         BufferedOutputStream  buffOut  =  
                 new   BufferedOutputStream ( out );

         if   (  requestedFile . exists ()   )   {
             System . out . println ( "workerID="   +  workerID  +  
                     ", 200 OK: "   +  filename );

             int  fileLen  =   ( int )  requestedFile . length ();

             BufferedInputStream  fileIn  =  
                 new   BufferedInputStream (
                     new   FileInputStream ( requestedFile ));

             // Use this utility to make a guess obout the
             // content type based on the first few bytes 
             // in the stream.
             String  contentType  =  
                 URLConnection . guessContentTypeFromStream (
                    fileIn );

             byte []  headerBytes  =  createHeaderBytes (
                     "HTTP/1.0 200 OK" ,  
                    fileLen ,
                    contentType
                 );

            buffOut . write ( headerBytes );

             byte []  buf  =   new   byte [ 2048 ];
             int  blockLen  =   0 ;

             while   (   (  blockLen  =  fileIn . read ( buf )   )   !=   - 1   )   {
                buffOut . write ( buf ,   0 ,  blockLen );
             }

            fileIn . close ();
         }   else   {
             System . out . println ( "workerID="   +  workerID  +  
                     ", 404 Not Found: "   +  filename  );

             byte []  headerBytes  =  createHeaderBytes (
                     "HTTP/1.0 404 Not Found" ,  
                     - 1 ,
                     null
                 );

            buffOut . write ( headerBytes );
         }

        buffOut . flush ();
     }

     private   File  generateFile ( String  filename )   {
         File  requestedFile  =  docRoot ;   // start at the base

         // Build up the path to the requested file in a 
         // platform independent way. URL's use '/' in their
         // path, but this platform may not.
         StringTokenizer  st  =   new   StringTokenizer ( filename ,   "/" );
         while   (  st . hasMoreTokens ()   )   {
             String  tok  =  st . nextToken ();

             if   (  tok . equals ( ".." )   )   {
                 // Silently ignore parts of path that might
                 // lead out of the document root area.
                 continue ;
             }

            requestedFile  =  
                 new   File ( requestedFile ,  tok );
         }

         if   (  requestedFile . exists ()   &&  
             requestedFile . isDirectory ()  
            )   {

             // If a directory was requested, modify the request
             // to look for the "index.html" file in that
             // directory.
            requestedFile  =  
                 new   File ( requestedFile ,   "index.html" );
         }

         return  requestedFile ;
     }

     private   byte []  createHeaderBytes (
                 String  resp ,  
                 int  contentLen ,
                 String  contentType
             )   throws   IOException   {

         ByteArrayOutputStream  baos  =   new   ByteArrayOutputStream ();
         BufferedWriter  writer  =   new   BufferedWriter (
                 new   OutputStreamWriter ( baos ));

         // Write the first line of the response, followed by
         // the RFC-specified line termination sequence.
        writer . write ( resp  +   "\r\n" );

         // If a length was specified, add it to the header
         if   (  contentLen  !=   - 1   )   {
            writer . write (
                 "Content-Length: "   +  contentLen  +   "\r\n" );
         }

         // If a type was specified, add it to the header
         if   (  contentType  !=   null   )   {
            writer . write (
                 "Content-Type: "   +  contentType  +   "\r\n" );
         }

         // A blank line is required after the header.
        writer . write ( "\r\n" );
        writer . flush ();

         byte []  data  =  baos . toByteArray ();
        writer . close ();

         return  data ;
     }

     public   void  stopRequest ()   {
        noStopRequested  =   false ;
        internalThread . interrupt ();
     }

     public   boolean  isAlive ()   {
         return  internalThread . isAlive ();
     }
}

source/chapter13/ObjectFIFO.java

source/chapter13/ObjectFIFO.java

public   class   ObjectFIFO   extends   Object   {
     private   Object []  queue ;
     private   int  capacity ;
     private   int  size ;
     private   int  head ;
     private   int  tail ;

     public   ObjectFIFO ( int  cap )   {
        capacity  =   (  cap  >   0   )   ?  cap  :   1 ;   // at least 1
        queue  =   new   Object [ capacity ];
        head  =   0 ;
        tail  =   0 ;
        size  =   0 ;
     }

     public   int  getCapacity ()   {
         return  capacity ;
     }

     public   synchronized   int  getSize ()   {
         return  size ;
     }

     public   synchronized   boolean  isEmpty ()   {
         return   (  size  ==   0   );
     }

     public   synchronized   boolean  isFull ()   {
         return   (  size  ==  capacity  );
     }

     public   synchronized   void  add ( Object  obj )  
             throws   InterruptedException   {

        waitWhileFull ();

        queue [ head ]   =  obj ;
        head  =   (  head  +   1   )   %  capacity ;
        size ++ ;

        notifyAll ();   // let any waiting threads know about change
     }

     public   synchronized   void  addEach ( Object []  list )  
             throws   InterruptedException   {

         //
         // You might want to code a more efficient 
         // implementation here ... (see ByteFIFO.java)
         //

         for   (   int  i  =   0 ;  i  <  list . length ;  i ++   )   {
            add ( list [ i ]);
         }
     }

     public   synchronized   Object  remove ()  
             throws   InterruptedException   {

        waitWhileEmpty ();
        
         Object  obj  =  queue [ tail ];

         // don't block GC by keeping unnecessary reference
        queue [ tail ]   =   null ;  

        tail  =   (  tail  +   1   )   %  capacity ;
        size -- ;

        notifyAll ();   // let any waiting threads know about change

         return  obj ;
     }

     public   synchronized   Object []  removeAll ()  
             throws   InterruptedException   {

         //
         // You might want to code a more efficient 
         // implementation here ... (see ByteFIFO.java)
         //

         Object []  list  =   new   Object [ size ];   // use the current size

         for   (   int  i  =   0 ;  i  <  list . length ;  i ++   )   {
            list [ i ]   =  remove ();
         }

         // if FIFO was empty, a zero-length array is returned
         return  list ;  
     }

     public   synchronized   Object []  removeAtLeastOne ()  
             throws   InterruptedException   {

        waitWhileEmpty ();   // wait for a least one to be in FIFO
         return  removeAll ();
     }

     public   synchronized   boolean  waitUntilEmpty ( long  msTimeout )  
             throws   InterruptedException   {

         if   (  msTimeout  ==   0L   )   {
            waitUntilEmpty ();    // use other method
             return   true ;
         }

         // wait only for the specified amount of time
         long  endTime  =   System . currentTimeMillis ()   +  msTimeout ;
         long  msRemaining  =  msTimeout ;

         while   (   ! isEmpty ()   &&   (  msRemaining  >   0L   )   )   {
            wait ( msRemaining );
            msRemaining  =  endTime  -   System . currentTimeMillis ();
         }

         // May have timed out, or may have met condition, 
         // calc return value.
         return  isEmpty ();
     }

     public   synchronized   void  waitUntilEmpty ()  
             throws   InterruptedException   {

         while   (   ! isEmpty ()   )   {
            wait ();
         }
     }

     public   synchronized   void  waitWhileEmpty ()  
             throws   InterruptedException   {

         while   (  isEmpty ()   )   {
            wait ();
         }
     }

     public   synchronized   void  waitUntilFull ()  
             throws   InterruptedException   {

         while   (   ! isFull ()   )   {
            wait ();
         }
     }

     public   synchronized   void  waitWhileFull ()  
             throws   InterruptedException   {

         while   (  isFull ()   )   {
            wait ();
         }
     }
}

source/chapter13/ThreadPool.java

source/chapter13/ThreadPool.java

// uses ObjectFIFO from chapter 18

public   class   ThreadPool   extends   Object   {
     private   ObjectFIFO  idleWorkers ;
     private   ThreadPoolWorker []  workerList ;

     public   ThreadPool ( int  numberOfThreads )   {
         // make sure that it's at least one
        numberOfThreads  =   Math . max ( 1 ,  numberOfThreads );

        idleWorkers  =   new   ObjectFIFO ( numberOfThreads );
        workerList  =   new   ThreadPoolWorker [ numberOfThreads ];

         for   (   int  i  =   0 ;  i  <  workerList . length ;  i ++   )   {
            workerList [ i ]   =   new   ThreadPoolWorker ( idleWorkers );
         }
     }

     public   void  execute ( Runnable  target )   throws   InterruptedException   {
         // block (forever) until a worker is available
         ThreadPoolWorker  worker  =   ( ThreadPoolWorker )  idleWorkers . remove ();
        worker . process ( target );
     }

     public   void  stopRequestIdleWorkers ()   {
         try   {
             Object []  idle  =  idleWorkers . removeAll ();
             for   (   int  i  =   0 ;  i  <  idle . length ;  i ++   )   {
                 (   ( ThreadPoolWorker )  idle [ i ]   ). stopRequest ();
             }
         }   catch   (   InterruptedException  x  )   {
             Thread . currentThread (). interrupt ();   // re-assert
         }
     }

     public   void  stopRequestAllWorkers ()   {
         // Stop the idle one's first since that won't interfere with anything
         // productive.
        stopRequestIdleWorkers ();

         // give the idle workers a quick chance to die 
         try   {   Thread . sleep ( 250 );   }   catch   (   InterruptedException  x  )   {   }
        
         // Step through the list of ALL workers that are still alive.
         for   (   int  i  =   0 ;  i  <  workerList . length ;  i ++   )   {
             if   (  workerList [ i ]. isAlive ()   )   {
                workerList [ i ]. stopRequest ();
             }
         }
     }
}

source/chapter13/ThreadPoolMain.java

source/chapter13/ThreadPoolMain.java

public   class   ThreadPoolMain   extends   Object   {

     public   static   Runnable  makeRunnable (
                 final   String  name ,  
                 final   long  firstDelay
             )   {

         return   new   Runnable ()   {
                 public   void  run ()   {
                     try   {
                         System . out . println ( name  + ": starting up" );
                         Thread . sleep ( firstDelay );
                         System . out . println ( name  +   ": doing some stuff" );
                         Thread . sleep ( 2000 );
                         System . out . println ( name  +   ": leaving" );
                     }   catch   (   InterruptedException  ix  )   {
                         System . out . println ( name  +   ": got interrupted!" );
                         return ;
                     }   catch   (   Exception  x  )   {
                        x . printStackTrace ();
                     }
                 }

                 public   String  toString ()   {
                     return  name ;
                 }
             };
     }

     public   static   void  main ( String []  args )   {
         try   {
             ThreadPool  pool  =   new   ThreadPool ( 3 );

             Runnable  ra  =  makeRunnable ( "RA" ,   3000 );
            pool . execute ( ra );

             Runnable  rb  =  makeRunnable ( "RB" ,   1000 );
            pool . execute ( rb );

             Runnable  rc  =  makeRunnable ( "RC" ,   2000 );
            pool . execute ( rc );

             Runnable  rd  =  makeRunnable ( "RD" ,   60000 );
            pool . execute ( rd );

             Runnable  re  =  makeRunnable ( "RE" ,   1000 );
            pool . execute ( re );

            pool . stopRequestIdleWorkers ();
             Thread . sleep ( 2000 );
            pool . stopRequestIdleWorkers ();

             Thread . sleep ( 5000 );
            pool . stopRequestAllWorkers ();
         }   catch   (   InterruptedException  ix  )   {
            ix . printStackTrace ();
         }
     }
}

source/chapter13/ThreadPoolWorker.java

source/chapter13/ThreadPoolWorker.java

// uses class ObjectFIFO from chapter 18

public   class   ThreadPoolWorker   extends   Object   {
     private   static   int  nextWorkerID  =   0 ;

     private   ObjectFIFO  idleWorkers ;
     private   int  workerID ;
     private   ObjectFIFO  handoffBox ;

     private   Thread  internalThread ;
     private   volatile   boolean  noStopRequested ;

     public   ThreadPoolWorker ( ObjectFIFO  idleWorkers )   {
         this . idleWorkers  =  idleWorkers ;

        workerID  =  getNextWorkerID ();
        handoffBox  =   new   ObjectFIFO ( 1 );   // only one slot

         // just before returning, the thread should be created and started.
        noStopRequested  =   true ;

         Runnable  r  =   new   Runnable ()   {
                 public   void  run ()   {
                     try   {
                        runWork ();
                     }   catch   (   Exception  x  )   {
                         // in case ANY exception slips through
                        x . printStackTrace ();  
                     }
                 }
             };

        internalThread  =   new   Thread ( r );
        internalThread . start ();
     }

     public   static   synchronized   int  getNextWorkerID ()   {  
         // notice: synchronized at the class level to ensure uniqueness
         int  id  =  nextWorkerID ;
        nextWorkerID ++ ;
         return  id ;
     }

     public   void  process ( Runnable  target )   throws   InterruptedException   {
        handoffBox . add ( target );
     }

     private   void  runWork ()   {
         while   (  noStopRequested  )   {
             try   {
                 System . out . println ( "workerID="   +  workerID  +  
                         ", ready for work" );
                 // Worker is ready work. This will never block since the
                 // idleWorker FIFO queue has enough capacity for all of
                 // the workers.
                idleWorkers . add ( this );

                 // wait here until the server puts a request into the box
                 Runnable  r  =   ( Runnable )  handoffBox . remove ();

                 System . out . println ( "workerID="   +  workerID  +  
                         ", starting execution of new Runnable: "   +  r );
                runIt ( r );   // catches all exceptions
             }   catch   (   InterruptedException  x  )   {
                 Thread . currentThread (). interrupt ();   // re-assert
             }
         }
     }

     private   void  runIt ( Runnable  r )   {
         try   {
            r . run ();
         }   catch   (   Exception  runex  )   {
             // catch any and all exceptions 
             System . err . println ( "Uncaught exception fell through from run()" );
            runex . printStackTrace ();
         }   finally   {
             // Clear the interrupted flag (in case it comes back set)
             // so that if the loop goes again, the 
             // handoffBox.remove() does not mistakenly throw
             // an InterruptedException.
             Thread . interrupted ();
         }
     }

     public   void  stopRequest ()   {
         System . out . println ( "workerID="   +  workerID  +  
                 ", stopRequest() received." );
        noStopRequested  =   false ;
        internalThread . interrupt ();
     }

     public   boolean  isAlive ()   {
         return  internalThread . isAlive ();
     }
}

source/chapter14/EarlyReturn.java

source/chapter14/EarlyReturn.java

public   class   EarlyReturn   extends   Object   {
     private   volatile   int  value ;

     public   EarlyReturn ( int  initialValue )   {
        value  =  initialValue ;
     }

     public   synchronized   void  setValue ( int  newValue )   {
         if   (  value  !=  newValue  )   {
            value  =  newValue ;
            notifyAll ();
         }
     }

     public   synchronized   boolean  waitUntilAtLeast (
                 int  minValue ,
                 long  msTimeout
             )   throws   InterruptedException   {

         System . out . println ( "entering waitUntilAtLeast() - "   +
                 "value="   +  value  +
                 ",minValue="   +  minValue );

         if   (  value  <  minValue  )   {
            wait ( msTimeout );
         }

         System . out . println ( "leaving waitUntilAtLeast() - "   +  
                 "value="   +  value  +
                 ",minValue="   +  minValue );

         // May have timed out, or may have met value, 
         // calc return value.
         return   (  value  >=  minValue  );
     }

     public   static   void  main ( String []  args )   {
         try   {
             final   EarlyReturn  er  =   new   EarlyReturn ( 0 );

             Runnable  r  =   new   Runnable ()   {
                     public   void  run ()   {
                         try   {
                             Thread . sleep ( 1500 );
                            er . setValue ( 2 );
                             Thread . sleep ( 500 );
                            er . setValue ( 3 );
                             Thread . sleep ( 500 );
                            er . setValue ( 4 );
                         }   catch   (   Exception  x  )   {
                            x . printStackTrace ();
                         }
                     }
                 };

             Thread  t  =   new   Thread ( r );
            t . start ();

             System . out . println (
                     "about to: waitUntilAtLeast(5, 3000)" );
             long  startTime  =   System . currentTimeMillis ();
             boolean  retVal  =  er . waitUntilAtLeast ( 5 ,   3000 );
             long  elapsedTime  =  
                     System . currentTimeMillis ()   -  startTime ;

             System . out . println ( "after "   +  elapsedTime  +  
                     " ms, retVal="   +  retVal );
         }   catch   (   InterruptedException  ix  )   {
            ix . printStackTrace ();
         }
     }
}

source/chapter14/EarlyReturnFix.java

source/chapter14/EarlyReturnFix.java

public   class   EarlyReturnFix   extends   Object   {
     private   volatile   int  value ;

     public   EarlyReturnFix ( int  initialValue )   {
        value  =  initialValue ;
     }

     public   synchronized   void  setValue ( int  newValue )   {
         if   (  value  !=  newValue  )   {
            value  =  newValue ;
            notifyAll ();
         }
     }

     public   synchronized   boolean  waitUntilAtLeast (
                 int  minValue ,
                 long  msTimeout
             )   throws   InterruptedException   {

         System . out . println ( "entering waitUntilAtLeast() - "   +  
                 "value="   +  value  +   ",minValue="   +  minValue );

         long  endTime  =   System . currentTimeMillis ()   +  msTimeout ;
         long  msRemaining  =  msTimeout ;

         while   (   (  value  <  minValue  )   &&   (  msRemaining  >   0L   )   )   {
             System . out . println ( "in waitUntilAtLeast() - "   +  
                     "about to: wait("   +  msRemaining  +   ")" );
            wait ( msRemaining );
            msRemaining  =  endTime  -   System . currentTimeMillis ();
             System . out . println ( "in waitUntilAtLeast() - "   +
                     "back from wait(), new msRemaining="   +
                    msRemaining );
         }

         System . out . println ( "leaving waitUntilAtLeast() - "   +
                 "value="   +  value  +   ",minValue="   +  minValue );

         // May have timed out, or may have met value, 
         // calc return value.
         return   (  value  >=  minValue  );
     }

     public   static   void  main ( String []  args )   {
         try   {
             final   EarlyReturnFix  er  =   new   EarlyReturnFix ( 0 );

             Runnable  r  =   new   Runnable ()   {
                     public   void  run ()   {
                         try   {
                             Thread . sleep ( 1500 );
                            er . setValue ( 2 );
                             Thread . sleep ( 500 );
                            er . setValue ( 3 );
                             Thread . sleep ( 500 );
                            er . setValue ( 4 );
                         }   catch   (   Exception  x  )   {
                            x . printStackTrace ();
                         }
                     }
                 };

             Thread  t  =   new   Thread ( r );
            t . start ();

             System . out . println (
                     "about to: waitUntilAtLeast(5, 3000)" );
             long  startTime  =   System . currentTimeMillis ();
             boolean  retVal  =  er . waitUntilAtLeast ( 5 ,   3000 );
             long  elapsedTime  =  
                     System . currentTimeMillis ()   -  startTime ;

             System . out . println ( "after "   +  elapsedTime  +  
                     " ms, retVal="   +  retVal );
         }   catch   (   InterruptedException  ix  )   {
            ix . printStackTrace ();
         }
     }
}

source/chapter14/FullWait.java

source/chapter14/FullWait.java

public   class   FullWait   extends   Object   {
     private   volatile   int  value ;

     public   FullWait ( int  initialValue )   {
        value  =  initialValue ;
     }

     public   synchronized   void  setValue ( int  newValue )   {
         if   (  value  !=  newValue  )   {
            value  =  newValue ;
            notifyAll ();
         }
     }

     public   synchronized   boolean  waitUntilAtLeast (
                 int  minValue ,
                 long  msTimeout
             )   throws   InterruptedException   {

         if   (  msTimeout  ==   0L   )   {
             while   (  value  <  minValue  )   {
                wait ();    // wait indefinitely until notified
             }

             // condition has finally been met
             return   true ;
         }  

         // only wait for the specified amount of time
         long  endTime  =   System . currentTimeMillis ()   +  msTimeout ;
         long  msRemaining  =  msTimeout ;

         while   (   (  value  <  minValue  )   &&   (  msRemaining  >   0L   )   )   {
            wait ( msRemaining );
            msRemaining  =  endTime  -   System . currentTimeMillis ();
         }

         // May have timed out, or may have met value, 
         // calc return value.
         return   (  value  >=  minValue  );
     }

     public   String  toString ()   {
         return  getClass (). getName ()   +   "[value="   +  value  +   "]" ;
     }
}

source/chapter14/FullWaitMain.java

source/chapter14/FullWaitMain.java

public   class   FullWaitMain   extends   Object   {
     private   FullWait  fullwait ;
     private   Thread  internalThread ;
     private   volatile   boolean  noStopRequested ;

     public   FullWaitMain ( FullWait  fw )   {
        fullwait  =  fw ;

        noStopRequested  =   true ;
         Runnable  r  =   new   Runnable ()   {
                 public   void  run ()   {
                     try   {
                        runWork ();
                     }   catch   (   Exception  x  )   {
                        x . printStackTrace ();  
                     }
                 }
             };

        internalThread  =   new   Thread ( r );
        internalThread . start ();
     }

     private   void  runWork ()   {
         int  count  =   6 ;

         while   (  noStopRequested  )   {
            fullwait . setValue ( count );
             System . out . println ( "just set value to "   +  count );
            count ++ ;

             try   {
                 Thread . sleep ( 1000 );
             }   catch   (   InterruptedException  x  )   {
                 // reassert interrupt
                 Thread . currentThread (). interrupt ();
             }
         }
     }

     public   void  stopRequest ()   {
        noStopRequested  =   false ;
        internalThread . interrupt ();
     }

     public   boolean  isAlive ()   {
         return  internalThread . isAlive ();
     }

     public   static   void  waitfor ( FullWait  fw ,   int  val ,   long  limit )  
                 throws   InterruptedException   {

         System . out . println ( "about to waitUntilAtLeast("   +  
                val  +   ", "   +  limit  +   ") ... " );

         long  startTime  =   System . currentTimeMillis ();
         boolean  retVal  =  fw . waitUntilAtLeast ( val ,  limit );
         long  endTime  =   System . currentTimeMillis ();

         System . out . println ( "waited for "   +  
                 (  endTime  -  startTime  )   +  
                 " ms, retVal="   +  retVal  +   "\n---------------" );
     }

     public   static   void  main ( String []  args )   {
         try   {
             FullWait  fw  =   new   FullWait ( 5 );
             FullWaitMain  fwm  =   new   FullWaitMain ( fw );

             Thread . sleep ( 500 );

             // should return true before 10 seconds
            waitfor ( fw ,   10 ,   10000L );  

             // should return true right away --already >= 6
            waitfor ( fw ,   6 ,   5000L );

             // should return true right away
             //   --already >= 6 (negative time ignored)
            waitfor ( fw ,   6 ,   - 1000L );

             // should return false right away --not there 
             // yet & negative time
            waitfor ( fw ,   15 ,   - 1000L );

             // should return false after 5 seconds
            waitfor ( fw ,   999 ,   5000L );

             // should eventually return true
            waitfor ( fw ,   20 ,   0L );

            fwm . stopRequest ();
         }   catch   (   InterruptedException  x  )   {
             System . err . println ( "*unexpectedly* interrupted "   +
                     "somewhere in main()" );
         }
     }
}

source/chapter15/BufferedThreadedInputStream.java

source/chapter15/BufferedThreadedInputStream.java

import  java . io . * ;

// uses ThreadedInputStream

public   class   BufferedThreadedInputStream  
         extends   FilterInputStream   {

     // fixed class that does *not* have a synchronized close()
     private   static   class   BISFix   extends   BufferedInputStream   {
         public   BISFix ( InputStream  rawIn ,   int  buffSize )   {
             super ( rawIn ,  buffSize );
         }

         public   void  close ()   throws   IOException   {
             if   (  in  !=   null   )   {
                 try   {
                    in . close ();
                 }   finally   {
                    in  =   null ;
                 }
             }
         }
     }

     public   BufferedThreadedInputStream (
                 InputStream  rawIn ,  
                 int  bufferSize
             )   {

         super ( rawIn );   // super-class' "in" is set below

         // rawIn -> BufferedIS -> ThreadedIS -> 
         //       BufferedIS -> read()

         BISFix  bis  =   new   BISFix ( rawIn ,  bufferSize );
         ThreadedInputStream  tis  =  
                 new   ThreadedInputStream ( bis ,  bufferSize );

         // Change the protected variable 'in' from the 
         // superclass from rawIn to the correct stream.
        in  =   new   BISFix ( tis ,  bufferSize );
     }

     public   BufferedThreadedInputStream ( InputStream  rawIn )   {
         this ( rawIn ,   2048 );
     }

     // Overridden to show that InterruptedIOException might 
     // be thrown.
     public   int  read ()  
             throws   InterruptedIOException ,   IOException   {

         return  in . read ();
     }

     // Overridden to show that InterruptedIOException might 
     // be thrown.
     public   int  read ( byte []  b )  
             throws   InterruptedIOException ,   IOException   {

         return  in . read ( b );
     }

     // Overridden to show that InterruptedIOException might 
     // be thrown.
     public   int  read ( byte []  b ,   int  off ,   int  len )  
             throws   InterruptedIOException ,   IOException   {

         return  in . read ( b ,  off ,  len );
     }

     // Overridden to show that InterruptedIOException might 
     // be thrown.
     public   long  skip ( long  n )  
             throws   InterruptedIOException ,   IOException   {

         return  in . skip ( n );
     }

     // The remainder of the methods are directly inherited from 
     // FilterInputStream and access "in" in the much the same 
     // way as the methods above do.
}

source/chapter15/ByteFIFO.java

source/chapter15/ByteFIFO.java

public   class   ByteFIFO   extends   Object   {
     private   byte []  queue ;
     private   int  capacity ;
     private   int  size ;
     private   int  head ;
     private   int  tail ;

     public   ByteFIFO ( int  cap )   {
        capacity  =   (  cap  >   0   )   ?  cap  :   1 ;   // at least 1
        queue  =   new   byte [ capacity ];
        head  =   0 ;
        tail  =   0 ;
        size  =   0 ;
     }

     public   int  getCapacity ()   {
         return  capacity ;
     }

     public   synchronized   int  getSize ()   {
         return  size ;
     }

     public   synchronized   boolean  isEmpty ()   {
         return   (  size  ==   0   );
     }

     public   synchronized   boolean  isFull ()   {
         return   (  size  ==  capacity  );
     }

     public   synchronized   void  add ( byte  b )  
             throws   InterruptedException   {

        waitWhileFull ();

        queue [ head ]   =  b ;
        head  =   (  head  +   1   )   %  capacity ;
        size ++ ;

        notifyAll ();   // let any waiting threads know about change
     }

     public   synchronized   void  add ( byte []  list )  
             throws   InterruptedException   {

         // For efficiency, the bytes are copied in blocks
         // instead of one at a time. As space becomes available,
         // more bytes are copied until all of them have been
         // added.

         int  ptr  =   0 ;

         while   (  ptr  <  list . length  )   {
             // If full, the lock will be released to allow 
             // another thread to come in and remove bytes.
            waitWhileFull ();

             int  space  =  capacity  -  size ;
             int  distToEnd  =  capacity  -  head ;
             int  blockLen  =   Math . min ( space ,  distToEnd );

             int  bytesRemaining  =  list . length  -  ptr ;
             int  copyLen  =   Math . min ( blockLen ,  bytesRemaining );

             System . arraycopy ( list ,  ptr ,  queue ,  head ,  copyLen );
            head  =   (  head  +  copyLen  )   %  capacity ;
            size  +=  copyLen ;
            ptr  +=  copyLen ;

             // Keep the lock, but let any waiting threads 
             // know that something has changed.
            notifyAll ();
         }
     }

     public   synchronized   byte  remove ()  
             throws   InterruptedException   {

        waitWhileEmpty ();
        
         byte  b  =  queue [ tail ];
        tail  =   (  tail  +   1   )   %  capacity ;
        size -- ;

        notifyAll ();   // let any waiting threads know about change

         return  b ;
     }

     public   synchronized   byte []  removeAll ()   {
         // For efficiency, the bytes are copied in blocks
         // instead of one at a time. 

         if   (  isEmpty ()   )   {
             // Nothing to remove, return a zero-length
             // array and do not bother with notification
             // since nothing was removed.
             return   new   byte [ 0 ];  
         }

         // based on the current size
         byte []  list  =   new   byte [ size ];  

         // copy in the block from tail to the end
         int  distToEnd  =  capacity  -  tail ;
         int  copyLen  =   Math . min ( size ,  distToEnd );
         System . arraycopy ( queue ,  tail ,  list ,   0 ,  copyLen );

         // If data wraps around, copy the remaining data
         // from the front of the array.
         if   (  size  >  copyLen  )   {
             System . arraycopy (
                    queue ,   0 ,  list ,  copyLen ,  size  -  copyLen );
         }

        tail  =   (  tail  +  size  )   %  capacity ;
        size  =   0 ;   // everything has been removed

         // Signal any and all waiting threads that 
         // something has changed.
        notifyAll ();  

         return  list ;  
     }

     public   synchronized   byte []  removeAtLeastOne ()  
             throws   InterruptedException   {

        waitWhileEmpty ();   // wait for a least one to be in FIFO
         return  removeAll ();
     }

     public   synchronized   boolean  waitUntilEmpty ( long  msTimeout )  
             throws   InterruptedException   {

         if   (  msTimeout  ==   0L   )   {
            waitUntilEmpty ();    // use other method
             return   true ;
         }

         // wait only for the specified amount of time
         long  endTime  =   System . currentTimeMillis ()   +  msTimeout ;
         long  msRemaining  =  msTimeout ;

         while   (   ! isEmpty ()   &&   (  msRemaining  >   0L   )   )   {
            wait ( msRemaining );
            msRemaining  =  endTime  -   System . currentTimeMillis ();
         }

         // May have timed out, or may have met condition, 
         // calc return value.
         return  isEmpty ();
     }

     public   synchronized   void  waitUntilEmpty ()  
             throws   InterruptedException   {

         while   (   ! isEmpty ()   )   {
            wait ();
         }
     }

     public   synchronized   void  waitWhileEmpty ()  
             throws   InterruptedException   {

         while   (  isEmpty ()   )   {
            wait ();
         }
     }

     public   synchronized   void  waitUntilFull ()  
             throws   InterruptedException   {

         while   (   ! isFull ()   )   {
            wait ();
         }
     }

     public   synchronized   void  waitWhileFull ()  
             throws   InterruptedException   {

         while   (  isFull ()   )   {
            wait ();
         }
     }
}

source/chapter15/CalcClient.java

source/chapter15/CalcClient.java

import  java . io . * ;
import  java . net . * ;

public   class   CalcClient   extends   Object   {
     public   static   void  main ( String []  args )   {
         String  hostname  =   "localhost" ;
         int  port  =   2001 ;

         try   {
             Socket  sock  =   new   Socket ( hostname ,  port );

             DataInputStream  in  =   new   DataInputStream (
                 new   BufferedInputStream ( sock . getInputStream ()));
             DataOutputStream  out  =   new   DataOutputStream (
                 new   BufferedOutputStream ( sock . getOutputStream ()));

             double  val  =   4.0 ;
            out . writeDouble ( val );
            out . flush ();

             double  sqrt  =  in . readDouble ();
             System . out . println ( "sent up "   +  val  +   ", got back "   +  sqrt );

             // Don't ever send another request, but stay alive in
             // this eternally blocked state.
             Object  lock  =   new   Object ();
             while   (   true   )   {
                 synchronized   (  lock  )   {
                    lock . wait ();
                 }
             }
         }   catch   (   Exception  x  )   {
            x . printStackTrace ();
         }
     }
}

source/chapter15/CalcServer.java

source/chapter15/CalcServer.java

import  java . io . * ;
import  java . net . * ;
import  java . util . * ;

public   class   CalcServer   extends   Object   {
     private   ServerSocket  ss ;
     private   List  workerList ;
    
     private   Thread  internalThread ;
     private   volatile   boolean  noStopRequested ;

     public   CalcServer ( int  port )   throws   IOException   {
        ss  =   new   ServerSocket ( port );
        workerList  =   new   LinkedList ();

        noStopRequested  =   true ;
         Runnable  r  =   new   Runnable ()   {
                 public   void  run ()   {
                     try   {
                        runWork ();
                     }   catch   (   Exception  x  )   {
                         // in case ANY exception slips through
                        x . printStackTrace ();  
                     }
                 }
             };

        internalThread  =   new   Thread ( r );
        internalThread . start ();
     }

     private   void  runWork ()   {
         System . out . println (
                 "in CalcServer - ready to accept connections" );

         while   (  noStopRequested  )   {
             try   {
                 System . out . println (
                         "in CalcServer - about to block "   +
                         "waiting for a new connection" );
                 Socket  sock  =  ss . accept ();
                 System . out . println (
                     "in CalcServer - received new connection" );
                workerList . add ( new   CalcWorker ( sock ));
             }   catch   (   IOException  iox  )   {
                 if   (  noStopRequested  )   {
                    iox . printStackTrace ();
                 }
             }
         }

         // stop all the workers that were created
         System . out . println ( "in CalcServer - putting in a "   +
                 "stop request to all the workers" );
         Iterator  iter  =  workerList . iterator ();
         while   (  iter . hasNext ()   )   {
             CalcWorker  worker  =   ( CalcWorker )  iter . next ();
            worker . stopRequest ();
         }

         System . out . println ( "in CalcServer - leaving runWork()" );
     }

     public   void  stopRequest ()   {
         System . out . println (
                 "in CalcServer - entering stopRequest()" );
        noStopRequested  =   false ;
        internalThread . interrupt ();

         if   (  ss  !=   null   )   {
             try   {
                ss . close ();
             }   catch   (   IOException  x  )   {
                 // ignore
             }   finally   {
                ss  =   null ;
             }
         }
     }

     public   boolean  isAlive ()   {
         return  internalThread . isAlive ();
     }

     public   static   void  main ( String []  args )   {
         int  port  =   2001 ;

         try   {
             CalcServer  server  =   new   CalcServer ( port );
             Thread . sleep ( 15000 );
            server . stopRequest ();
         }   catch   (   IOException  x  )   {
            x . printStackTrace ();
         }   catch   (   InterruptedException  x  )   {
             // ignore
         }
     }
}

source/chapter15/CalcServerTwo.java

source/chapter15/CalcServerTwo.java

import  java . io . * ;
import  java . net . * ;
import  java . util . * ;

public   class   CalcServerTwo   extends   Object   {
     private   ServerSocket  ss ;
     private   List  workerList ;
    
     private   Thread  internalThread ;
     private   volatile   boolean  noStopRequested ;

     public   CalcServerTwo ( int  port )   throws   IOException   {
        ss  =   new   ServerSocket ( port );
        workerList  =   new   LinkedList ();

        noStopRequested  =   true ;
         Runnable  r  =   new   Runnable ()   {
                 public   void  run ()   {
                     try   {
                        runWork ();
                     }   catch   (   Exception  x  )   {
                         // in case ANY exception slips through
                        x . printStackTrace ();  
                     }
                 }
             };

        internalThread  =   new   Thread ( r );
        internalThread . start ();
     }

     private   void  runWork ()   {
         System . out . println (
                 "in CalcServer - ready to accept connections" );

         while   (  noStopRequested  )   {
             try   {
                 System . out . println (
                         "in CalcServer - about to block "   +
                         "waiting for a new connection" );
                 Socket  sock  =  ss . accept ();
                 System . out . println (
                     "in CalcServer - received new connection" );
                workerList . add ( new   CalcWorkerTwo ( sock ));
             }   catch   (   IOException  iox  )   {
                 if   (  noStopRequested  )   {
                    iox . printStackTrace ();
                 }
             }
         }

         // stop all the workers that were created
         System . out . println ( "in CalcServer - putting in a "   +
                 "stop request to all the workers" );
         Iterator  iter  =  workerList . iterator ();
         while   (  iter . hasNext ()   )   {
             CalcWorkerTwo  worker  =   ( CalcWorkerTwo )  iter . next ();
            worker . stopRequest ();
         }

         System . out . println ( "in CalcServer - leaving runWork()" );
     }

     public   void  stopRequest ()   {
         System . out . println (
                 "in CalcServer - entering stopRequest()" );
        noStopRequested  =   false ;
        internalThread . interrupt ();

         if   (  ss  !=   null   )   {
             try   {
                ss . close ();
             }   catch   (   IOException  x  )   {
                 // ignore
             }   finally   {
                ss  =   null ;
             }
         }
     }

     public   boolean  isAlive ()   {
         return  internalThread . isAlive ();
     }

     public   static   void  main ( String []  args )   {
         int  port  =   2001 ;

         try   {
             CalcServerTwo  server  =   new   CalcServerTwo ( port );
             Thread . sleep ( 15000 );
            server . stopRequest ();
         }   catch   (   IOException  x  )   {
            x . printStackTrace ();
         }   catch   (   InterruptedException  x  )   {
             // ignore
         }
     }
}

source/chapter15/CalcWorker.java

source/chapter15/CalcWorker.java

import  java . io . * ;
import  java . net . * ;

public   class   CalcWorker   extends   Object   {
     private   InputStream  sockIn ;
     private   OutputStream  sockOut ;
     private   DataInputStream  dataIn ;
     private   DataOutputStream  dataOut ;
    
     private   Thread  internalThread ;
     private   volatile   boolean  noStopRequested ;

     public   CalcWorker ( Socket  sock )   throws   IOException   {
        sockIn  =  sock . getInputStream ();
        sockOut  =  sock . getOutputStream ();

        dataIn  =   new   DataInputStream (
                 new   BufferedInputStream ( sockIn ));
        dataOut  =   new   DataOutputStream (
                 new   BufferedOutputStream ( sockOut ));

        noStopRequested  =   true ;
         Runnable  r  =   new   Runnable ()   {
                 public   void  run ()   {
                     try   {
                        runWork ();
                     }   catch   (   Exception  x  )   {
                         // in case ANY exception slips through
                        x . printStackTrace ();  
                     }
                 }
             };

        internalThread  =   new   Thread ( r );
        internalThread . start ();
     }

     private   void  runWork ()   {
         while   (  noStopRequested  )   {
             try   {
                 System . out . println ( "in CalcWorker - about to "   +
                         "block waiting to read a double" );
                 double  val  =  dataIn . readDouble ();
                 System . out . println (
                         "in CalcWorker - read a double!" );
                dataOut . writeDouble ( Math . sqrt ( val ));
                dataOut . flush ();
             }   catch   (   IOException  x  )   {
                 if   (  noStopRequested  )   {
                    x . printStackTrace ();
                    stopRequest ();
                 }
             }
         }

         // In real-world code, be sure to close other streams and
         // the socket as part of the clean-up. Omitted here for
         // brevity.

         System . out . println ( "in CalcWorker - leaving runWork()" );
     }

     public   void  stopRequest ()   {
         System . out . println (
                 "in CalcWorker - entering stopRequest()" );
        noStopRequested  =   false ;
        internalThread . interrupt ();

         if   (  sockIn  !=   null   )   {
             try   {
                sockIn . close ();
             }   catch   (   IOException  iox  )   {
                 // ignore
             }   finally   {
                sockIn  =   null ;
             }
         }

         System . out . println (
                 "in CalcWorker - leaving stopRequest()" );
     }

     public   boolean  isAlive ()   {
         return  internalThread . isAlive ();
     }
}

source/chapter15/CalcWorkerTwo.java

source/chapter15/CalcWorkerTwo.java

import  java . io . * ;
import  java . net . * ;

public   class   CalcWorkerTwo   extends   Object   {
     private   DataInputStream  dataIn ;
     private   DataOutputStream  dataOut ;
    
     private   Thread  internalThread ;
     private   volatile   boolean  noStopRequested ;

     public   CalcWorkerTwo ( Socket  sock )   throws   IOException   {
        dataIn  =   new   DataInputStream (
             new   BufferedThreadedInputStream (
                sock . getInputStream ()));
        dataOut  =   new   DataOutputStream (
             new   BufferedOutputStream (
                sock . getOutputStream ()));

        noStopRequested  =   true ;
         Runnable  r  =   new   Runnable ()   {
                 public   void  run ()   {
                     try   {
                        runWork ();
                     }   catch   (   Exception  x  )   {
                         // in case ANY exception slips through
                        x . printStackTrace ();  
                     }
                 }
             };

        internalThread  =   new   Thread ( r );
        internalThread . start ();
     }

     private   void  runWork ()   {
         while   (  noStopRequested  )   {
             try   {
                 System . out . println ( "in CalcWorker - about to "   +
                         "block waiting to read a double" );
                 double  val  =  dataIn . readDouble ();
                 System . out . println (
                         "in CalcWorker - read a double!" );
                dataOut . writeDouble ( Math . sqrt ( val ));
                dataOut . flush ();
             }   catch   (   InterruptedIOException  iiox  )   {
                 System . out . println ( "in CalcWorker - blocked "   +
                         "read was interrupted!!!" );
             }   catch   (   IOException  x  )   {
                 if   (  noStopRequested  )   {
                    x . printStackTrace ();
                    stopRequest ();
                 }
             }
         }

         // In real-world code, be sure to close other streams 
         // and the socket as part of the clean-up. Omitted here 
         // for brevity.

         System . out . println ( "in CalcWorker - leaving runWork()" );
     }

     public   void  stopRequest ()   {
         System . out . println (
                 "in CalcWorker - entering stopRequest()" );
        noStopRequested  =   false ;
        internalThread . interrupt ();
         System . out . println (
                 "in CalcWorker - leaving stopRequest()" );
     }

     public   boolean  isAlive ()   {
         return  internalThread . isAlive ();
     }
}

source/chapter15/DefiantStream.java

source/chapter15/DefiantStream.java

import  java . io . * ;

public   class   DefiantStream   extends   Object   {
     public   static   void  main ( String []  args )   {
         final   InputStream  in  =   System . in ;

         Runnable  r  =   new   Runnable ()   {
                 public   void  run ()   {
                     try   {
                         System . err . println (
                                 "about to try to read from in" );
                        in . read ();
                         System . err . println ( "just read from in" );
                     }   catch   (   InterruptedIOException  iiox  )   {
                        iiox . printStackTrace ();
                     }   catch   (   IOException  iox  )   {
                        iox . printStackTrace ();
                     //} catch ( InterruptedException ix ) { 
                     //  InterruptedException is never thrown!
                     //  ix.printStackTrace();
                     }   catch   (   Exception  x  )   {
                        x . printStackTrace ();
                     }   finally   {
                         Thread  currThread  =  
                                 Thread . currentThread ();
                         System . err . println ( "inside finally:\n"   +
                             "  currThread="   +  currThread  +   "\n"   +
                             "  currThread.isAlive()="   +  
                            currThread . isAlive ());
                     }
                 }
             };
        
         Thread  t  =   new   Thread ( r );
        t . start ();

         try   {   Thread . sleep ( 2000 );   }  
         catch   (   InterruptedException  x  )   {   }

         System . err . println ( "about to interrupt thread" );
        t . interrupt ();
         System . err . println ( "just interrupted thread" );

         try   {   Thread . sleep ( 2000 );   }  
         catch   (   InterruptedException  x  )   {   }

         System . err . println ( "about to stop thread" );
         // stop() is being used here to show that the extreme
         // action of stopping a thread is also ineffective. 
         // Because stop() is deprecated, the compiler issues
         // a warning.
        t . stop ();  
         System . err . println ( "just stopped thread, t.isAlive()="   +
                t . isAlive ());

         try   {   Thread . sleep ( 2000 );   }  
         catch   (   InterruptedException  x  )   {   }

         System . err . println ( "t.isAlive()="   +  t . isAlive ());
         System . err . println ( "leaving main()" );
     }
}

source/chapter15/SureStop.java

source/chapter15/SureStop.java

import  java . util . * ;

public   class   SureStop   extends   Object   {
     // nested internal class for stop request entries
     private   static   class   Entry   extends   Object   {
         private   Thread  thread ;
         private   long  stopTime ;

         private   Entry ( Thread  t ,   long  stop )   {
            thread  =  t ;
            stopTime  =  stop ;
         }
     }

     // static reference to the singleton instance
     private   static   SureStop  ss ;

     static   {
         // When class is loaded, create exactly one instance 
         // using the private constructor.
        ss  =   new   SureStop ();
     }

     private   List  stopList ;
     private   List  pendingList ;
     private   Thread  internalThread ;

     private   SureStop ()   {
         // using a linked list for fast deletions
        stopList  =   new   LinkedList ();

         // Enough initial capacity for 20 pending additions, 
         // will grow automatically if necessary to keep 
         // ensureStop() from blocking.
        pendingList  =   new   ArrayList ( 20 );

         Runnable  r  =   new   Runnable ()   {
                 public   void  run ()   {
                     try   {
                        runWork ();
                     }   catch   (   Exception  x  )   {
                         // in case ANY exception slips through
                        x . printStackTrace ();  
                     }
                 }
             };

        internalThread  =   new   Thread ( r );
        internalThread . setDaemon ( true );   // no need to run alone
        internalThread . setPriority ( Thread . MAX_PRIORITY );   // high
        internalThread . start ();
     }

     private   void  runWork ()   {
         try   {
             while   (   true   )   {
                 // Since this is a super-high priority thread, 
                 // be sure to give other threads a chance to 
                 // run each time through in case the wait on 
                 // pendingList is very short.
                 Thread . sleep ( 500 );

                 // Stop expired threads and determine the 
                 // amount of time until the next thread is
                 // due to expire.
                 long  sleepTime  =  checkStopList ();

                 synchronized   (  pendingList  )   {
                     if   (  pendingList . size ()   <   1   )   {
                        pendingList . wait ( sleepTime );
                     }

                     if   (  pendingList . size ()   >   0   )   {
                         // Copy into stopList and then remove 
                         // from pendingList.
                        stopList . addAll ( pendingList );
                        pendingList . clear ();
                     }
                 }
             }   // while
         }   catch   (   InterruptedException  x  )   {
             // ignore
         }   catch   (   Exception  x  )   {
             // Never expect this, but print a trace in case 
             // it happens.
            x . printStackTrace ();
         }
     }

     private   long  checkStopList ()   {
         // called from runWork() by the internal thread 

         long  currTime  =   System . currentTimeMillis ();
         long  minTime  =   Long . MAX_VALUE ;

         Iterator  iter  =  stopList . iterator ();
         while   (  iter . hasNext ()   )   {
             Entry  entry  =   ( Entry )  iter . next ();

             if   (  entry . thread . isAlive ()   )   {
                 if   (  entry . stopTime  <  currTime  )   {
                     // timed out, stop it abruptly right now
                     try   {
                        entry . thread . stop ();
                     }   catch   (   SecurityException  x  )   {
                         // Catch this here so that other 
                         // operations are not disrupted. Warn
                         // that thread could not be stopped.
                         System . err . println (
                             "SureStop was not permitted to "   +
                             "stop thread="   +  entry . thread );
                        x . printStackTrace ();
                     }

                     // Since it has stopped, remove it 
                     // from stopList.
                    iter . remove ();
                 }   else   {
                     // Not yet expired, check to see if this 
                     // is the new minimum.
                    minTime  =   Math . min ( entry . stopTime ,  minTime );
                 }
             }   else   {
                 // Thread died on its own, remove it from 
                 // stopList.
                iter . remove ();
             }   // if alive
         }   // while

         long  sleepTime  =  minTime  -   System . currentTimeMillis ();

         // ensure that it is a least a little bit of time
        sleepTime  =   Math . max ( 50 ,  sleepTime );  

         return  sleepTime ;
     }

     private   void  addEntry ( Entry  entry )   {
         // called from ensureStop() by external thread

         synchronized   (  pendingList  )   {
            pendingList . add ( entry );

             // no need for notifyAll(), one waiter
            pendingList . notify ();  
         }
     }

     public   static   void  ensureStop ( Thread  t ,   long  msGracePeriod )   {
         if   (   ! t . isAlive ()   )   {
             // thread is already stopped, return right away
             return ;
         }

         long  stopTime  =  
                 System . currentTimeMillis ()   +  msGracePeriod ;

         Entry  entry  =   new   Entry ( t ,  stopTime );
        ss . addEntry ( entry );
     }
}

source/chapter15/ThreadedInputStream.java

source/chapter15/ThreadedInputStream.java

import  java . io . * ;

// uses SureStop from chapter 16
// uses ByteFIFO from chapter 18

public   class   ThreadedInputStream   extends   FilterInputStream   {
     private   ByteFIFO  buffer ;

     private   volatile   boolean  closeRequested ;
     private   volatile   boolean  eofDetected ;
     private   volatile   boolean  ioxDetected ;
     private   volatile   String  ioxMessage ;

     private   Thread  internalThread ;
     private   volatile   boolean  noStopRequested ;

     public   ThreadedInputStream ( InputStream  in ,   int  bufferSize )   {
         super ( in );

        buffer  =   new   ByteFIFO ( bufferSize );

        closeRequested  =   false ;
        eofDetected  =   false ;
        ioxDetected  =   false ;
        ioxMessage  =   null ;

        noStopRequested  =   true ;
         Runnable  r  =   new   Runnable ()   {
                 public   void  run ()   {
                     try   {
                        runWork ();
                     }   catch   (   Exception  x  )   {
                         // in case ANY exception slips through
                        x . printStackTrace ();  
                     }
                 }
             };

        internalThread  =   new   Thread ( r );
        internalThread . setDaemon ( true );
        internalThread . start ();
     }

     public   ThreadedInputStream ( InputStream  in )   {
         this ( in ,   2048 );
     }

     private   void  runWork ()   {
         byte []  workBuf  =   new   byte [ buffer . getCapacity ()];

         try   {
             while   (  noStopRequested  )   {
                 int  readCount  =  in . read ( workBuf );

                 if   (  readCount  ==   - 1   )   {
                    signalEOF ();
                    stopRequest ();
                 }   else   if   (  readCount  >   0   )   {
                    addToBuffer ( workBuf ,  readCount );
                 }
             }
         }   catch   (   IOException  iox  )   {
             if   (   ! closeRequested  )   {
                ioxMessage  =  iox . getMessage ();
                signalIOX ();
             }
         }   catch   (   InterruptedException  x  )   {
             // ignore
         }   finally   {
             // no matter what, make sure that eofDetected is set
            signalEOF ();
         }
     }

     private   void  signalEOF ()   {
         synchronized   (  buffer  )   {
            eofDetected  =   true ;
            buffer . notifyAll ();
         }
     }

     private   void  signalIOX ()   {
         synchronized   (  buffer  )   {
            ioxDetected  =   true ;
            buffer . notifyAll ();
         }
     }
    
     private   void  signalClose ()   {
         synchronized   (  buffer  )   {
            closeRequested  =   true ;
            buffer . notifyAll ();
         }
     }

     private   void  addToBuffer ( byte []  workBuf ,   int  readCount )  
             throws   InterruptedException   {

         // Create an array exactly as large as the number of
         // bytes read and copy the data into it.
         byte []  addBuf  =   new   byte [ readCount ];
         System . arraycopy ( workBuf ,   0 ,  addBuf ,   0 ,  addBuf . length );

        buffer . add ( addBuf );
     }

     private   void  stopRequest ()   {
         if   (  noStopRequested  )   {
            noStopRequested  =   false ;
            internalThread . interrupt ();
         }
     }

     public   void  close ()   throws   IOException   {
         if   (  closeRequested  )   {
             // already closeRequested, just return
             return ;
         }
        signalClose ();

         SureStop . ensureStop ( internalThread ,   10000 );
        stopRequest ();

         // Use a new thread to close "in" in case it blocks
         final   InputStream  localIn  =  in ;
         Runnable  r  =   new   Runnable ()   {
                 public   void  run ()   {
                     try   {
                        localIn . close ();
                     }   catch   (   IOException  iox  )   {
                         // ignore
                     }
                 }
             };

         Thread  t  =   new   Thread ( r ,   "in-close" );
         // give up when all other non-daemon threads die
        t . setDaemon ( true );   
        t . start ();
     }

     private   void  throwExceptionIfClosed ()   throws   IOException   {
         if   (  closeRequested  )   {
             throw   new   IOException ( "stream is closed" );
         }
     }

     // Throws InterruptedIOException if the thread blocked on
     // read() is interrupted while waiting for data to arrive.
     public   int  read ()  
             throws   InterruptedIOException ,   IOException   {

         // Using read(byte[]) to keep code in one place --makes
         // single-byte read less efficient, but simplifies 
         // the coding.
         byte []  data  =   new   byte [ 1 ];
         int  ret  =  read ( data ,   0 ,   1 );

         if   (  ret  !=   1   )   {
             return   - 1 ;
         }

         return  data [ 0 ]   &   0x000000FF ;
     }

     // Throws InterruptedIOException if the thread blocked on
     // read() is interrupted while waiting for data to arrive.
     public   int  read ( byte []  dest )  
             throws   InterruptedIOException ,   IOException   {

         return  read ( dest ,   0 ,  dest . length );
     }

     // Throws InterruptedIOException if the thread blocked on
     // read() is interrupted while waiting for data to arrive.
     public   int  read (
                 byte []  dest ,  
                 int  offset ,  
                 int  length
             )   throws   InterruptedIOException ,   IOException   {

        throwExceptionIfClosed ();

         if   (  length  <   1   )   {
             return   0 ;
         }

         if   (   (  offset  <   0   )   ||  
              (   (  offset  +  length  )   >  dest . length  )  
            )   {

             throw   new   IllegalArgumentException (
                 "offset must be at least 0, and "   +
                 "(offset + length) must be less than or "   +
                 "equal to dest.length. "   +
                 "offset="   +  offset  +  
                 ", (offset + length )="   +   (  offset  +  length  )   +
                 ", dest.length="   +  dest . length );
         }

         byte []  data  =  removeUpTo ( length );

         if   (  data . length  >   0   )   {
             System . arraycopy ( data ,   0 ,  dest ,  offset ,  data . length );
             return  data . length ;
         }

         // no data
         if   (  eofDetected  )   {
             return   - 1 ;
         }

         // no data and not end of file, must be exception
        stopRequest ();

         if   (  ioxMessage  ==   null   )   {
            ioxMessage  =   "stream cannot be read" ;
         }

         throw   new   IOException ( ioxMessage );
     }

     private   byte []  removeUpTo ( int  maxRead )   throws   IOException   {
         // Convenience method to assist read(byte[], int, int).
         // Waits until at least one byte is ready, EOF is 
         // detected,  an IOException is thrown, or the 
         // stream is closed.
         try   {
             synchronized   (  buffer  )   {
                 while   (  buffer . isEmpty ()   &&  
                         ! eofDetected  &&  
                         ! ioxDetected  &&
                         ! closeRequested
                       )   {
    
                    buffer . wait ();
                 }
    
                 // If stream was closed while waiting, 
                 // get out right away.
                throwExceptionIfClosed ();
    
                 // Ignore eof and exception flags for now, see 
                 // if any data remains.
                 byte []  data  =  buffer . removeAll ();
    
                 if   (  data . length  >  maxRead  )   {
                     // Pulled out too many bytes, 
                     // put excess back.
                     byte []  putBackData  =  
                             new   byte [ data . length  -  maxRead ];
                     System . arraycopy ( data ,  maxRead ,  
                            putBackData ,   0 ,  putBackData . length );
                    buffer . add ( putBackData );
    
                     byte []  keepData  =   new   byte [ maxRead ];
                     System . arraycopy ( data ,   0 ,  
                            keepData ,   0 ,  keepData . length );
                    data  =  keepData ;
                 }
    
                 return  data ;
             }
         }   catch   (   InterruptedException  ix  )   {
             // convert to an IOException
             throw   new   InterruptedIOException ( "interrupted "   +
                 "while waiting for data to arrive for reading" );
         }
     }

     public   long  skip ( long  n )   throws   IOException   {
        throwExceptionIfClosed ();

         if   (  n  <=   0   )   {
             return   0 ;
         }

         int  skipLen  =   ( int )   Math . min ( n ,   Integer . MAX_VALUE );
         int  readCount  =  read ( new   byte [ skipLen ]);

         if   (  readCount  <   0   )   {
             return   0 ;
         }

         return  readCount ;
     }

     public   int  available ()   throws   IOException   {
        throwExceptionIfClosed ();
         return  buffer . getSize ();
     }

     public   boolean  markSupported ()   {
         return   false ;
     }

     public   synchronized   void  mark ( int  readLimit )   {
         // ignore method calls, mark not supported
     }

     public   synchronized   void  reset ()   throws   IOException   {
         throw   new   IOException (
                 "mark-reset not supported on this stream" );
     }
}

source/chapter16/SureStop.java

source/chapter16/SureStop.java

import  java . util . * ;

public   class   SureStop   extends   Object   {
     // nested internal class for stop request entries
     private   static   class   Entry   extends   Object   {
         private   Thread  thread ;
         private   long  stopTime ;

         private   Entry ( Thread  t ,   long  stop )   {
            thread  =  t ;
            stopTime  =  stop ;
         }
     }

     // static reference to the singleton instance
     private   static   SureStop  ss ;

     static   {
         // When class is loaded, create exactly one instance 
         // using the private constructor.
        ss  =   new   SureStop ();
     }

     private   List  stopList ;
     private   List  pendingList ;
     private   Thread  internalThread ;

     private   SureStop ()   {
         // using a linked list for fast deletions
        stopList  =   new   LinkedList ();

         // Enough initial capacity for 20 pending additions, 
         // will grow automatically if necessary to keep 
         // ensureStop() from blocking.
        pendingList  =   new   ArrayList ( 20 );

         Runnable  r  =   new   Runnable ()   {
                 public   void  run ()   {
                     try   {
                        runWork ();
                     }   catch   (   Exception  x  )   {
                         // in case ANY exception slips through
                        x . printStackTrace ();  
                     }
                 }
             };

        internalThread  =   new   Thread ( r );
        internalThread . setDaemon ( true );   // no need to run alone
        internalThread . setPriority ( Thread . MAX_PRIORITY );   // high
        internalThread . start ();
     }

     private   void  runWork ()   {
         try   {
             while   (   true   )   {
                 // Since this is a super-high priority thread, 
                 // be sure to give other threads a chance to 
                 // run each time through in case the wait on 
                 // pendingList is very short.
                 Thread . sleep ( 500 );

                 // Stop expired threads and determine the 
                 // amount of time until the next thread is
                 // due to expire.
                 long  sleepTime  =  checkStopList ();

                 synchronized   (  pendingList  )   {
                     if   (  pendingList . size ()   <   1   )   {
                        pendingList . wait ( sleepTime );
                     }

                     if   (  pendingList . size ()   >   0   )   {
                         // Copy into stopList and then remove 
                         // from pendingList.
                        stopList . addAll ( pendingList );
                        pendingList . clear ();
                     }
                 }
             }   // while
         }   catch   (   InterruptedException  x  )   {
             // ignore
         }   catch   (   Exception  x  )   {
             // Never expect this, but print a trace in case 
             // it happens.
            x . printStackTrace ();
         }
     }

     private   long  checkStopList ()   {
         // called from runWork() by the internal thread 

         long  currTime  =   System . currentTimeMillis ();
         long  minTime  =   Long . MAX_VALUE ;

         Iterator  iter  =  stopList . iterator ();
         while   (  iter . hasNext ()   )   {
             Entry  entry  =   ( Entry )  iter . next ();

             if   (  entry . thread . isAlive ()   )   {
                 if   (  entry . stopTime  <  currTime  )   {
                     // timed out, stop it abruptly right now
                     try   {
                        entry . thread . stop ();
                     }   catch   (   SecurityException  x  )   {
                         // Catch this here so that other 
                         // operations are not disrupted. Warn
                         // that thread could not be stopped.
                         System . err . println (
                             "SureStop was not permitted to "   +
                             "stop thread="   +  entry . thread );
                        x . printStackTrace ();
                     }

                     // Since it has stopped, remove it 
                     // from stopList.
                    iter . remove ();
                 }   else   {
                     // Not yet expired, check to see if this 
                     // is the new minimum.
                    minTime  =   Math . min ( entry . stopTime ,  minTime );
                 }
             }   else   {
                 // Thread died on its own, remove it from 
                 // stopList.
                iter . remove ();
             }   // if alive
         }   // while

         long  sleepTime  =  minTime  -   System . currentTimeMillis ();

         // ensure that it is a least a little bit of time
        sleepTime  =   Math . max ( 50 ,  sleepTime );  

         return  sleepTime ;
     }

     private   void  addEntry ( Entry  entry )   {
         // called from ensureStop() by external thread

         synchronized   (  pendingList  )   {
            pendingList . add ( entry );

             // no need for notifyAll(), one waiter
            pendingList . notify ();  
         }
     }

     public   static   void  ensureStop ( Thread  t ,   long  msGracePeriod )   {
         if   (   ! t . isAlive ()   )   {
             // thread is already stopped, return right away
             return ;
         }

         long  stopTime  =  
                 System . currentTimeMillis ()   +  msGracePeriod ;

         Entry  entry  =   new   Entry ( t ,  stopTime );
        ss . addEntry ( entry );
     }
}

source/chapter16/SureStopDemo.java

source/chapter16/SureStopDemo.java

public   class   SureStopDemo   extends   Object   {
     private   static   Thread  launch (
                 final   String  name ,  
                 long  lifeTime
             )   {

         final   int  loopCount  =   ( int )   (  lifeTime  /   1000   );

         Runnable  r  =   new   Runnable ()   {
                 public   void  run ()   {
                     try   {
                         for   (   int  i  =   0 ;  i  <  loopCount ;  i ++   )   {
                             Thread . sleep ( 1000 );
                             System . out . println (
                                     "-> Running - "   +  name );
                         }
                     }   catch   (   InterruptedException  x  )   {
                         // ignore
                     }
                 }
             };
        
         Thread  t  =   new   Thread ( r );
        t . setName ( name );
        t . start ();

         return  t ;
     }

     public   static   void  main ( String []  args )   {
         Thread  t0  =  launch ( "T0" ,   1000 );
         Thread  t1  =  launch ( "T1" ,   5000 );
         Thread  t2  =  launch ( "T2" ,   15000 );

         try   {   Thread . sleep ( 2000 );   }  
         catch   (   InterruptedException  x  )   {   }

         SureStopVerbose . ensureStop ( t0 ,    9000 );
         SureStopVerbose . ensureStop ( t1 ,   10000 );
         SureStopVerbose . ensureStop ( t2 ,   12000 );

         try   {   Thread . sleep ( 20000 );   }  
         catch   (   InterruptedException  x  )   {   }

         Thread  t3  =  launch ( "T3" ,   15000 );
         SureStopVerbose . ensureStop ( t3 ,   5000 );

         try   {   Thread . sleep ( 1000 );   }  
         catch   (   InterruptedException  x  )   {   }

         Thread  t4  =  launch ( "T4" ,   15000 );
         SureStopVerbose . ensureStop ( t4 ,   3000 );
     }
}

source/chapter16/SureStopVerbose.java

source/chapter16/SureStopVerbose.java

import  java . util . * ;

public   class   SureStopVerbose   extends   Object   {
     // nested internal class for stop request entries
     private   static   class   Entry   extends   Object   {
         private   Thread  thread ;
         private   long  stopTime ;

         private   Entry ( Thread  t ,   long  stop )   {
            thread  =  t ;
            stopTime  =  stop ;
         }
     }

     // static reference to the singleton instance
     private   static   SureStopVerbose  ss ;

     static   {
         // When class is loaded, create exactly one instance 
         // using the private constructor.
        ss  =   new   SureStopVerbose ();
        print ( "SureStopVerbose instance created." );
     }

     private   List  stopList ;
     private   List  pendingList ;
     private   Thread  internalThread ;

     private   SureStopVerbose ()   {
         // using a linked list for fast deletions
        stopList  =   new   LinkedList ();

         // Enough initial capacity for 20 pending additions, 
         // will grow automatically if necessary to keep 
         // ensureStop() from blocking.
        pendingList  =   new   ArrayList ( 20 );

         Runnable  r  =   new   Runnable ()   {
                 public   void  run ()   {
                     try   {
                        runWork ();
                     }   catch   (   Exception  x  )   {
                         // in case ANY exception slips through
                        x . printStackTrace ();  
                     }
                 }
             };

        internalThread  =   new   Thread ( r );
        internalThread . setDaemon ( true );   // no need to run alone
        internalThread . setPriority ( Thread . MAX_PRIORITY );   // high
        internalThread . start ();
     }

     private   void  runWork ()   {
         try   {
             while   (   true   )   {
                 // Since this is a super-high priority thread, 
                 // be sure to give other threads a chance to 
                 // run each time through in case the wait on 
                 // pendingList is very short.
                print ( "about to sleep for 0.5 seconds" );
                 Thread . sleep ( 500 );
                print ( "done with sleep for 0.5 seconds" );

                 long  sleepTime  =  checkStopList ();
                print ( "back from checkStopList(), sleepTime="   +  
                        sleepTime );

                 synchronized   (  pendingList  )   {
                     if   (  pendingList . size ()   <   1   )   {
                        print ( "about to wait on pendingList "   +
                             "for "   +  sleepTime  +   " ms" );
                         long  start  =   System . currentTimeMillis ();
                        pendingList . wait ( sleepTime );
                         long  elapsedTime  =  
                             System . currentTimeMillis ()   -  start ;
                        print ( "waited on pendingList for "   +  
                            elapsedTime  +   " ms" );
                     }


                     if   (  pendingList . size ()   >   0   )   {
                         // copy into stopList and then remove 
                         // from pendingList.
                        print ( "copying "   +  pendingList . size ()   +  
                             " elements from pendingList to "   +
                             "stopList" );
                         int  oldSize  =  stopList . size ();
                        stopList . addAll ( pendingList );
                        pendingList . clear ();
                         int  newSize  =  stopList . size ();
                        print ( "pendingList.size()="   +  
                            pendingList . size ()   +
                             ", stopList grew by "   +  
                             ( newSize  -  oldSize ));
                     }
                 }
             }   // while
         }   catch   (   InterruptedException  x  )   {
             // ignore
         }   catch   (   Exception  x  )   {
             // Never expect this, but print a trace in case 
             // it happens.
            x . printStackTrace ();
         }
     }

     private   long  checkStopList ()   {
        print ( "entering checkStopList() - stopList.size()="   +  
                stopList . size ());
         long  currTime  =   System . currentTimeMillis ();
         long  minTime  =   Long . MAX_VALUE ;

         Iterator  iter  =  stopList . iterator ();
         while   (  iter . hasNext ()   )   {
             Entry  entry  =   ( Entry )  iter . next ();

             if   (  entry . thread . isAlive ()   )   {
                print ( "thread is alive - "   +  
                        entry . thread . getName ());
                 if   (  entry . stopTime  <  currTime  )   {
                     // timed out, stop it abruptly right now
                    print ( "timed out, stopping - "   +  
                            entry . thread . getName ());
                     try   {
                        entry . thread . stop ();
                     }   catch   (   SecurityException  x  )   {
                         // Catch this here so that other 
                         // operations are not disrupted. Warn 
                         // that thread could not be stopped.
                         System . err . println (
                             "SureStop was not permitted to "   +
                             "stop thread="   +  entry . thread );
                        x . printStackTrace ();
                     }

                     // Since it's stopped, remove it 
                     // from stopList.
                    iter . remove ();
                 }   else   {
                     // Not yet expired, check to see if this 
                     // is the new minimum.
                    minTime  =   Math . min ( entry . stopTime ,  minTime );
                    print ( "new minTime="   +  minTime );
                 }
             }   else   {
                print ( "thread died on its own - "   +  
                        entry . thread . getName ());
                 // Thread died on its own, remove it from 
                 // stopList.
                iter . remove ();
             }   // if alive
         }   // while

         long  sleepTime  =  minTime  -   System . currentTimeMillis ();

         // ensure that it is a least a little bit of time
        sleepTime  =   Math . max ( 50 ,  sleepTime );  

        print ( "leaving checkStopList() - stopList.size()="   +  
                stopList . size ());
         return  sleepTime ;
     }

     private   void  addEntry ( Entry  entry )   {
         synchronized   (  pendingList  )   {
            pendingList . add ( entry );

             // no need for notifyAll(), one waiter
            pendingList . notify ();  
            print ( "added entry to pendingList, name="   +  
                entry . thread . getName ()   +  
                 ", stopTime="   +  entry . stopTime  +   ", in "   +  
                 (  entry . stopTime  -   System . currentTimeMillis ()   )   +
                 " ms" );
         }
     }

     public   static   void  ensureStop ( Thread  t ,   long  msGracePeriod )   {
        print ( "entering ensureStop() - name="   +  t . getName ()   +
             ", msGracePeriod="   +  msGracePeriod );

         if   (   ! t . isAlive ()   )   {
             // thread is already stopped, return right away
            print ( "already stopped, not added to list - "   +  
                    t . getName ());
             return ;
         }

         long  stopTime  =  
                 System . currentTimeMillis ()   +  msGracePeriod ;
         Entry  entry  =   new   Entry ( t ,  stopTime );
        ss . addEntry ( entry );
        print ( "leaving ensureStop() - name="   +  t . getName ());
     }

     private   static   void  print ( String  msg )   {
         Thread  t  =   Thread . currentThread ();
         String  name  =  t . getName ();
         if   (  t  ==  ss . internalThread  )   {
            name  =   "SureStopThread" ;
         }

         System . out . println ( name  +   ": "   +  msg );
     }
}

source/chapter17/BooleanLock.java

source/chapter17/BooleanLock.java

public   class   BooleanLock   extends   Object   {
     private   boolean  value ;

     public   BooleanLock ( boolean  initialValue )   {
        value  =  initialValue ;
     }

     public   BooleanLock ()   {
         this ( false );
     }

     public   synchronized   void  setValue ( boolean  newValue )   {
         if   (  newValue  !=  value  )   {
            value  =  newValue ;
            notifyAll ();
         }
     }

     public   synchronized   boolean  waitToSetTrue ( long  msTimeout )  
             throws   InterruptedException   {

         boolean  success  =  waitUntilFalse ( msTimeout );
         if   (  success  )   {
            setValue ( true );
         }

         return  success ;
     }

     public   synchronized   boolean  waitToSetFalse ( long  msTimeout )  
             throws   InterruptedException   {

         boolean  success  =  waitUntilTrue ( msTimeout );
         if   (  success  )   {
            setValue ( false );
         }

         return  success ;
     }

     public   synchronized   boolean  isTrue ()   {
         return  value ;
     }

     public   synchronized   boolean  isFalse ()   {
         return   ! value ;
     }

     public   synchronized   boolean  waitUntilTrue ( long  msTimeout )  
             throws   InterruptedException   {

         return  waitUntilStateIs ( true ,  msTimeout );
     }

     public   synchronized   boolean  waitUntilFalse ( long  msTimeout )  
             throws   InterruptedException   {

         return  waitUntilStateIs ( false ,  msTimeout );
     }

     public   synchronized   boolean  waitUntilStateIs (
                 boolean  state ,  
                 long  msTimeout
             )   throws   InterruptedException   {

         if   (  msTimeout  ==   0L   )   {
             while   (  value  !=  state  )   {
                wait ();    // wait indefinitely until notified
             }

             // condition has finally been met
             return   true ;
         }  

         // only wait for the specified amount of time
         long  endTime  =   System . currentTimeMillis ()   +  msTimeout ;
         long  msRemaining  =  msTimeout ;

         while   (   (  value  !=  state  )   &&   (  msRemaining  >   0L   )   )   {
            wait ( msRemaining );
            msRemaining  =  endTime  -   System . currentTimeMillis ();
         }

         // May have timed out, or may have met value, 
         // calculate return value.
         return   (  value  ==  state  );
     }
}

source/chapter17/InterruptibleSyncBlock.java

source/chapter17/InterruptibleSyncBlock.java

public   class   InterruptibleSyncBlock   extends   Object   {
     private   Object  longLock ;
     private   BooleanLock  busyLock ;

     public   InterruptibleSyncBlock ()   {
        longLock  =   new   Object ();
        busyLock  =   new   BooleanLock ( false );
     }

     public   void  doStuff ()   throws   InterruptedException   {
        print ( "about to try to get exclusive access "   +
                 "to busyLock" );
        busyLock . waitToSetTrue ( 0 );

         try   {
            print ( "about to try to get exclusive access "   +
                     "to longLock" );
             synchronized   (  longLock  )   {
                print ( "got exclusive access to longLock" );
                 try   {  
                     Thread . sleep ( 10000 );  
                 }   catch   (   InterruptedException  x  )   {  
                     // ignore
                 }
                print ( "about to relinquish exclusive access "   +
                         "to longLock" );
             }
         }   finally   {
            print ( "about to free up busyLock" );
            busyLock . setValue ( false );
         }
     }

     private   static   void  print ( String  msg )   {
         String  name  =   Thread . currentThread (). getName ();
         System . err . println ( name  +   ": "   +  msg );
     }

     private   static   Thread  launch (
                 final   InterruptibleSyncBlock  sb ,  
                 String  name
             )   {

         Runnable  r  =   new   Runnable ()   {
                 public   void  run ()   {
                    print ( "in run()" );
                     try   {
                        sb . doStuff ();
                     }   catch   (   InterruptedException  x  )   {
                        print ( "InterruptedException thrown "   +
                                 "from doStuff()" );
                     }
                 }
             };
        
         Thread  t  =   new   Thread ( r ,  name );
        t . start ();

         return  t ;
     }

     public   static   void  main ( String []  args )   {
         try   {
             InterruptibleSyncBlock  sb  =  
                     new   InterruptibleSyncBlock ();
    
             Thread  t1  =  launch ( sb ,   "T1" );
             Thread . sleep ( 500 );

             Thread  t2  =  launch ( sb ,   "T2" );
             Thread  t3  =  launch ( sb ,   "T3" );

             Thread . sleep ( 1000 );

            print ( "about to interrupt T2" );
            t2 . interrupt ();
            print ( "just interrupted T2" );

         }   catch   (   InterruptedException  x  )   {
            x . printStackTrace ();
         }
     }
}

source/chapter17/Signaling.java

source/chapter17/Signaling.java

public   class   Signaling   extends   Object   {
     private   BooleanLock  readyLock ;

     public   Signaling ( BooleanLock  readyLock )   {
         this . readyLock  =  readyLock ;

         Runnable  r  =   new   Runnable ()   {
                 public   void  run ()   {
                     try   {
                        runWork ();
                     }   catch   (   Exception  x  )   {
                         // in case ANY exception slips through
                        x . printStackTrace ();  
                     }
                 }
             };

         Thread  internalThread  =   new   Thread ( r ,   "internal" );
        internalThread . start ();
     }
    
     private   void  runWork ()   {
         try   {
            print ( "about to wait for readyLock to be true" );
            readyLock . waitUntilTrue ( 0 );    // 0 - wait forever
            print ( "readyLock is now true" );
         }   catch   (   InterruptedException  x  )   {
            print ( "interrupted while waiting for readyLock "   +
                     "to become true" );
         }
     }

     private   static   void  print ( String  msg )   {
         String  name  =   Thread . currentThread (). getName ();
         System . err . println ( name  +   ": "   +  msg );
     }

     public   static   void  main ( String []  args )   {
         try   {
            print ( "creating BooleanLock instance" );
             BooleanLock  ready  =   new   BooleanLock ( false );
        
            print ( "creating Signaling instance" );
             new   Signaling ( ready );

            print ( "about to sleep for 3 seconds" );
             Thread . sleep ( 3000 );

            print ( "about to setValue to true" );
            ready . setValue ( true );
            print ( "ready.isTrue()="   +  ready . isTrue ());
         }   catch   (   InterruptedException  x  )   {
            x . printStackTrace ();
         }
     }
}

source/chapter17/SyncBlock.java

source/chapter17/SyncBlock.java

public   class   SyncBlock   extends   Object   {
     private   Object  longLock ;

     public   SyncBlock ()   {
        longLock  =   new   Object ();
     }

     public   void  doStuff ()   {
        print ( "about to try to get exclusive access "   +
                 "to longLock" );

         synchronized   (  longLock  )   {
            print ( "got exclusive access to longLock" );
             try   {   Thread . sleep ( 10000 );   }  
             catch   (   InterruptedException  x  )   {   }
            print ( "about to relinquish exclusive access to "   +
                     "longLock" );
         }
     }

     private   static   void  print ( String  msg )   {
         String  name  =   Thread . currentThread (). getName ();
         System . err . println ( name  +   ": "   +  msg );
     }

     private   static   Thread  launch (
                 final   SyncBlock  sb ,  
                 String  name
             )   {

         Runnable  r  =   new   Runnable ()   {
                 public   void  run ()   {
                    print ( "in run()" );
                    sb . doStuff ();
                 }
             };
        
         Thread  t  =   new   Thread ( r ,  name );
        t . start ();

         return  t ;
     }

     public   static   void  main ( String []  args )   {
         try   {
             SyncBlock  sb  =   new   SyncBlock ();
    
             Thread  t1  =  launch ( sb ,   "T1" );
             Thread . sleep ( 500 );

             Thread  t2  =  launch ( sb ,   "T2" );
             Thread  t3  =  launch ( sb ,   "T3" );

             Thread . sleep ( 1000 );

            print ( "about to interrupt T2" );
            t2 . interrupt ();
            print ( "just interrupted T2" );

         }   catch   (   InterruptedException  x  )   {
            x . printStackTrace ();
         }
     }
}

source/chapter17/TransitionDetector.java

source/chapter17/TransitionDetector.java

public   class   TransitionDetector   extends   Object   {
     private   boolean  value ;
     private   Object  valueLock ;
     private   Object  falseToTrueLock ;
     private   Object  trueToFalseLock ;

     public   TransitionDetector ( boolean  initialValue )   {
        value  =  initialValue ;
        valueLock  =   new   Object ();
        falseToTrueLock  =   new   Object ();
        trueToFalseLock  =   new   Object ();
     }

     public   void  setValue ( boolean  newValue )   {
         synchronized   (  valueLock  )   {
             if   (  newValue  !=  value  )   {
                value  =  newValue ;
                
                 if   (  value  )   {
                    notifyFalseToTrueWaiters ();
                 }   else   {
                    notifyTrueToFalseWaiters ();
                 }
             }
         }
     }

     public   void  pulseValue ()   {
         // Sync on valueLock to be sure that no other threads 
         // get into setValue() between these two setValue() 
         // calls.
         synchronized   (  valueLock  )   {
            setValue ( ! value );
            setValue ( ! value );
         }
     }

     public   boolean  isTrue ()   {
         synchronized   (  valueLock  )   {
             return  value ;
         }
     }

     public   void  waitForFalseToTrueTransition ()  
             throws   InterruptedException   {

         synchronized   (  falseToTrueLock  )   {
            falseToTrueLock . wait ();
         }
     }

     private   void  notifyFalseToTrueWaiters ()   {
         synchronized   (  falseToTrueLock  )   {
            falseToTrueLock . notifyAll ();
         }
     }

     public   void  waitForTrueToFalseTransition ()  
             throws   InterruptedException   {

         synchronized   (  trueToFalseLock  )   {
            trueToFalseLock . wait ();
         }
     }

     private   void  notifyTrueToFalseWaiters ()   {
         synchronized   (  trueToFalseLock  )   {
            trueToFalseLock . notifyAll ();
         }
     }

     public   String  toString ()   {
         return   String . valueOf ( isTrue ());
     }
}

source/chapter17/TransitionDetectorMain.java

source/chapter17/TransitionDetectorMain.java

public   class   TransitionDetectorMain   extends   Object   {
     private   static   Thread  startTrueWaiter (
                 final   TransitionDetector  td ,
                 String  name
             )   {

         Runnable  r  =   new   Runnable ()   {
                 public   void  run ()   {
                     try   {
                         while   (   true   )   {
                            print ( "about to wait for false-to-"   +
                                 "true transition, td="   +  td );

                            td . waitForFalseToTrueTransition ();

                            print ( "just noticed for false-to-"   +
                                 "true transition, td="   +  td );
                         }
                     }   catch   (   InterruptedException  ix  )   {
                         return ;
                     }
                 }
             };

         Thread  t  =   new   Thread ( r ,  name );
        t . start ();

         return  t ;
     }

     private   static   Thread  startFalseWaiter (
                 final   TransitionDetector  td ,
                 String  name
             )   {

         Runnable  r  =   new   Runnable ()   {
                 public   void  run ()   {
                     try   {
                         while   (   true   )   {
                            print ( "about to wait for true-to-"   +
                                 "false transition, td="   +  td );

                            td . waitForTrueToFalseTransition ();

                            print ( "just noticed for true-to-"   +
                                 "false transition, td="   +  td );
                         }
                     }   catch   (   InterruptedException  ix  )   {
                         return ;
                     }
                 }
             };

         Thread  t  =   new   Thread ( r ,  name );
        t . start ();

         return  t ;
     }

     private   static   void  print ( String  msg )   {
         String  name  =   Thread . currentThread (). getName ();
         System . err . println ( name  +   ": "   +  msg );
     }

     public   static   void  main ( String []  args )   {
         try   {
             TransitionDetector  td  =  
                     new   TransitionDetector ( false );

             Thread  threadA  =  startTrueWaiter ( td ,   "threadA" );
             Thread  threadB  =  startFalseWaiter ( td ,   "threadB" );

             Thread . sleep ( 200 );
            print ( "td="   +  td  +   ", about to set to 'false'" );
            td . setValue ( false );

             Thread . sleep ( 200 );
            print ( "td="   +  td  +   ", about to set to 'true'" );
            td . setValue ( true );

             Thread . sleep ( 200 );
            print ( "td="   +  td  +   ", about to pulse value" );
            td . pulseValue ();

             Thread . sleep ( 200 );
            threadA . interrupt ();
            threadB . interrupt ();
         }   catch   (   InterruptedException  x  )   {
            x . printStackTrace ();
         }
     }
}

source/chapter18/ByteFIFO.java

source/chapter18/ByteFIFO.java

public   class   ByteFIFO   extends   Object   {
     private   byte []  queue ;
     private   int  capacity ;
     private   int  size ;
     private   int  head ;
     private   int  tail ;

     public   ByteFIFO ( int  cap )   {
        capacity  =   (  cap  >   0   )   ?  cap  :   1 ;   // at least 1
        queue  =   new   byte [ capacity ];
        head  =   0 ;
        tail  =   0 ;
        size  =   0 ;
     }

     public   int  getCapacity ()   {
         return  capacity ;
     }

     public   synchronized   int  getSize ()   {
         return  size ;
     }

     public   synchronized   boolean  isEmpty ()   {
         return   (  size  ==   0   );
     }

     public   synchronized   boolean  isFull ()   {
         return   (  size  ==  capacity  );
     }

     public   synchronized   void  add ( byte  b )  
             throws   InterruptedException   {

        waitWhileFull ();

        queue [ head ]   =  b ;
        head  =   (  head  +   1   )   %  capacity ;
        size ++ ;

        notifyAll ();   // let any waiting threads know about change
     }

     public   synchronized   void  add ( byte []  list )  
             throws   InterruptedException   {

         // For efficiency, the bytes are copied in blocks
         // instead of one at a time. As space becomes available,
         // more bytes are copied until all of them have been
         // added.

         int  ptr  =   0 ;

         while   (  ptr  <  list . length  )   {
             // If full, the lock will be released to allow 
             // another thread to come in and remove bytes.
            waitWhileFull ();

             int  space  =  capacity  -  size ;
             int  distToEnd  =  capacity  -  head ;
             int  blockLen  =   Math . min ( space ,  distToEnd );

             int  bytesRemaining  =  list . length  -  ptr ;
             int  copyLen  =   Math . min ( blockLen ,  bytesRemaining );

             System . arraycopy ( list ,  ptr ,  queue ,  head ,  copyLen );
            head  =   (  head  +  copyLen  )   %  capacity ;
            size  +=  copyLen ;
            ptr  +=  copyLen ;

             // Keep the lock, but let any waiting threads 
             // know that something has changed.
            notifyAll ();
         }
     }

     public   synchronized   byte  remove ()  
             throws   InterruptedException   {

        waitWhileEmpty ();
        
         byte  b  =  queue [ tail ];
        tail  =   (  tail  +   1   )   %  capacity ;
        size -- ;

        notifyAll ();   // let any waiting threads know about change

         return  b ;
     }

     public   synchronized   byte []  removeAll ()   {
         // For efficiency, the bytes are copied in blocks
         // instead of one at a time. 

         if   (  isEmpty ()   )   {
             // Nothing to remove, return a zero-length
             // array and do not bother with notification
             // since nothing was removed.
             return   new   byte [ 0 ];  
         }

         // based on the current size
         byte []  list  =   new   byte [ size ];  

         // copy in the block from tail to the end
         int  distToEnd  =  capacity  -  tail ;
         int  copyLen  =   Math . min ( size ,  distToEnd );
         System . arraycopy ( queue ,  tail ,  list ,   0 ,  copyLen );

         // If data wraps around, copy the remaining data
         // from the front of the array.
         if   (  size  >  copyLen  )   {
             System . arraycopy (
                    queue ,   0 ,  list ,  copyLen ,  size  -  copyLen );
         }

        tail  =   (  tail  +  size  )   %  capacity ;
        size  =   0 ;   // everything has been removed

         // Signal any and all waiting threads that 
         // something has changed.
        notifyAll ();  

         return  list ;  
     }

     public   synchronized   byte []  removeAtLeastOne ()  
             throws   InterruptedException   {

        waitWhileEmpty ();   // wait for a least one to be in FIFO
         return  removeAll ();
     }

     public   synchronized   boolean  waitUntilEmpty ( long  msTimeout )  
             throws   InterruptedException   {

         if   (  msTimeout  ==   0L   )   {
            waitUntilEmpty ();    // use other method
             return   true ;
         }

         // wait only for the specified amount of time
         long  endTime  =   System . currentTimeMillis ()   +  msTimeout ;
         long  msRemaining  =  msTimeout ;

         while   (   ! isEmpty ()   &&   (  msRemaining  >   0L   )   )   {
            wait ( msRemaining );
            msRemaining  =  endTime  -   System . currentTimeMillis ();
         }

         // May have timed out, or may have met condition, 
         // calc return value.
         return  isEmpty ();
     }

     public   synchronized   void  waitUntilEmpty ()  
             throws   InterruptedException   {

         while   (   ! isEmpty ()   )   {
            wait ();
         }
     }

     public   synchronized   void  waitWhileEmpty ()  
             throws   InterruptedException   {

         while   (  isEmpty ()   )   {
            wait ();
         }
     }

     public   synchronized   void  waitUntilFull ()  
             throws   InterruptedException   {

         while   (   ! isFull ()   )   {
            wait ();
         }
     }

     public   synchronized   void  waitWhileFull ()  
             throws   InterruptedException   {

         while   (  isFull ()   )   {
            wait ();
         }
     }
}

source/chapter18/ByteFIFOTest.java

source/chapter18/ByteFIFOTest.java

import  java . io . * ;

public   class   ByteFIFOTest   extends   Object   {
     private   ByteFIFO  fifo ;
     private   byte []  srcData ;

     public   ByteFIFOTest ()   throws   IOException   {
        fifo  =   new   ByteFIFO ( 20 );

        makeSrcData ();
         System . out . println ( "srcData.length="   +  srcData . length );

         Runnable  srcRunnable  =   new   Runnable ()   {
                 public   void  run ()   {
                    src ();
                 }
             };
         Thread  srcThread  =   new   Thread ( srcRunnable );
        srcThread . start ();

         Runnable  dstRunnable  =   new   Runnable ()   {
                 public   void  run ()   {
                    dst ();
                 }
             };
         Thread  dstThread  =   new   Thread ( dstRunnable );
        dstThread . start ();
     }

     private   void  makeSrcData ()   throws   IOException   {
         String []  list  =   {
                 "The first string is right here" ,
                 "The second string is a bit longer and also right here" ,
                 "The third string" ,
                 "ABCDEFGHIJKLMNOPQRSTUVWXYZ" ,
                 "0123456789" ,
                 "The last string in the list"
             };

         ByteArrayOutputStream  baos  =   new   ByteArrayOutputStream ();
         ObjectOutputStream  oos  =   new   ObjectOutputStream ( baos );
        oos . writeObject ( list );
        oos . flush ();
        oos . close ();
        
        srcData  =  baos . toByteArray ();
     }

     private   void  src ()   {
         try   {
             boolean  justAddOne  =   true ;
             int  count  =   0 ;

             while   (  count  <  srcData . length  )   {
                 if   (   ! justAddOne  )   {
                     int  writeSize  =   ( int )   (   40.0   *   Math . random ()   );
                    writeSize  =   Math . min ( writeSize ,  srcData . length  -  count );

                     byte []  buf  =   new   byte [ writeSize ];
                     System . arraycopy ( srcData ,  count ,  buf ,   0 ,  writeSize );
                    fifo . add ( buf );
                    count  +=  writeSize ;

                     System . out . println ( "just added "   +  writeSize  +   " bytes" );
                 }   else   {
                    fifo . add ( srcData [ count ]);
                    count ++ ;

                     System . out . println ( "just added exactly 1 byte" );
                 }

                justAddOne  =   ! justAddOne ;
             }
         }   catch   (   InterruptedException  x  )   {
            x . printStackTrace ();
         }
     }

     private   void  dst ()   {
         try   {
             boolean  justAddOne  =   true ;
             int  count  =   0 ;
             byte []  dstData  =   new   byte [ srcData . length ];

             while   (  count  <  dstData . length  )   {
                 if   (   ! justAddOne  )   {
                     byte []  buf  =  fifo . removeAll ();
                     if   (  buf . length  >   0   )   {
                         System . arraycopy ( buf ,   0 ,  dstData ,  count ,  buf . length );
                        count  +=  buf . length ;
                     }

                     System . out . println (
                         "just removed "   +  buf . length  +   " bytes" );
                 }   else   {
                     byte  b  =  fifo . remove ();
                    dstData [ count ]   =  b ;
                    count ++ ;

                     System . out . println (
                         "just removed exactly 1 byte" );
                 }

                justAddOne  =   ! justAddOne ;
             }

             System . out . println ( "received all data, count="   +  count );

             ObjectInputStream  ois  =   new   ObjectInputStream (
                     new   ByteArrayInputStream ( dstData ));

             String []  line  =   ( String [])  ois . readObject ();

             for   (   int  i  =   0 ;  i  <  line . length ;  i ++   )   {
                 System . out . println ( "line["   +  i  +   "]="   +  line [ i ]);
             }
         }   catch   (   ClassNotFoundException  x1  )   {
            x1 . printStackTrace ();
         }   catch   (   IOException  iox  )   {
            iox . printStackTrace ();
         }   catch   (   InterruptedException  x  )   {
            x . printStackTrace ();
         }
     }

     public   static   void  main ( String []  args )   {
         try   {
             new   ByteFIFOTest ();
         }   catch   (   IOException  iox  )   {
            iox . printStackTrace ();
         }
     }
}

source/chapter18/ObjectFIFO.java

source/chapter18/ObjectFIFO.java

public   class   ObjectFIFO   extends   Object   {
     private   Object []  queue ;
     private   int  capacity ;
     private   int  size ;
     private   int  head ;
     private   int  tail ;

     public   ObjectFIFO ( int  cap )   {
        capacity  =   (  cap  >   0   )   ?  cap  :   1 ;   // at least 1
        queue  =   new   Object [ capacity ];
        head  =   0 ;
        tail  =   0 ;
        size  =   0 ;
     }

     public   int  getCapacity ()   {
         return  capacity ;
     }

     public   synchronized   int  getSize ()   {
         return  size ;
     }

     public   synchronized   boolean  isEmpty ()   {
         return   (  size  ==   0   );
     }

     public   synchronized   boolean  isFull ()   {
         return   (  size  ==  capacity  );
     }

     public   synchronized   void  add ( Object  obj )  
             throws   InterruptedException   {

        waitWhileFull ();

        queue [ head ]   =  obj ;
        head  =   (  head  +   1   )   %  capacity ;
        size ++ ;

        notifyAll ();   // let any waiting threads know about change
     }

     public   synchronized   void  addEach ( Object []  list )  
             throws   InterruptedException   {

         //
         // You might want to code a more efficient 
         // implementation here ... (see ByteFIFO.java)
         //

         for   (   int  i  =   0 ;  i  <  list . length ;  i ++   )   {
            add ( list [ i ]);
         }
     }

     public   synchronized   Object  remove ()  
             throws   InterruptedException   {

        waitWhileEmpty ();
        
         Object  obj  =  queue [ tail ];

         // don't block GC by keeping unnecessary reference
        queue [ tail ]   =   null ;  

        tail  =   (  tail  +   1   )   %  capacity ;
        size -- ;

        notifyAll ();   // let any waiting threads know about change

         return  obj ;
     }

     public   synchronized   Object []  removeAll ()  
             throws   InterruptedException   {

         //
         // You might want to code a more efficient 
         // implementation here ... (see ByteFIFO.java)
         //

         Object []  list  =   new   Object [ size ];   // use the current size

         for   (   int  i  =   0 ;  i  <  list . length ;  i ++   )   {
            list [ i ]   =  remove ();
         }

         // if FIFO was empty, a zero-length array is returned
         return  list ;  
     }

     public   synchronized   Object []  removeAtLeastOne ()  
             throws   InterruptedException   {

        waitWhileEmpty ();   // wait for a least one to be in FIFO
         return  removeAll ();
     }

     public   synchronized   boolean  waitUntilEmpty ( long  msTimeout )  
             throws   InterruptedException   {

         if   (  msTimeout  ==   0L   )   {
            waitUntilEmpty ();    // use other method
             return   true ;
         }

         // wait only for the specified amount of time
         long  endTime  =   System . currentTimeMillis ()   +  msTimeout ;
         long  msRemaining  =  msTimeout ;

         while   (   ! isEmpty ()   &&   (  msRemaining  >   0L   )   )   {
            wait ( msRemaining );
            msRemaining  =  endTime  -   System . currentTimeMillis ();
         }

         // May have timed out, or may have met condition, 
         // calc return value.
         return  isEmpty ();
     }

     public   synchronized   void  waitUntilEmpty ()  
             throws   InterruptedException   {

         while   (   ! isEmpty ()   )   {
            wait ();
         }
     }

     public   synchronized   void  waitWhileEmpty ()  
             throws   InterruptedException   {

         while   (  isEmpty ()   )   {
            wait ();
         }
     }

     public   synchronized   void  waitUntilFull ()  
             throws   InterruptedException   {

         while   (   ! isFull ()   )   {
            wait ();
         }
     }

     public   synchronized   void  waitWhileFull ()  
             throws   InterruptedException   {

         while   (  isFull ()   )   {
            wait ();
         }
     }
}

source/chapter18/ObjectFIFOTest.java

source/chapter18/ObjectFIFOTest.java

public   class   ObjectFIFOTest   extends   Object   {
    
     private   static   void  fullCheck ( ObjectFIFO  fifo )   {
         try   {
             // Sync'd to allow messages to print while 
             // condition is still true.
             synchronized   (  fifo  )   {
                 while   (   true   )   {
                    fifo . waitUntilFull ();
                    print ( "FULL" );
                    fifo . waitWhileFull ();
                    print ( "NO LONGER FULL" );
                 }
             }
         }   catch   (   InterruptedException  ix  )   {
             return ;
         }
     }

     private   static   void  emptyCheck ( ObjectFIFO  fifo )   {
         try   {
             // Sync'd to allow messages to print while 
             // condition is still true.
             synchronized   (  fifo  )   {
                 while   (   true   )   {
                    fifo . waitUntilEmpty ();
                    print ( "EMPTY" );
                    fifo . waitWhileEmpty ();
                    print ( "NO LONGER EMPTY" );
                 }
             }
         }   catch   (   InterruptedException  ix  )   {
             return ;
         }
     }

     private   static   void  consumer ( ObjectFIFO  fifo )   {
         try   {
            print ( "just entered consumer()" );

             for   (   int  i  =   0 ;  i  <   3 ;  i ++   )   {
                 synchronized   (  fifo  )   {
                     Object  obj  =  fifo . remove ();
                    print ( "DATA-OUT - did remove(), obj="   +  obj );
                 }
                 Thread . sleep ( 3000 );
             }

             synchronized   (  fifo  )   {
                 boolean  resultOfWait  =  fifo . waitUntilEmpty ( 500 );
                print ( "did waitUntilEmpty(500), resultOfWait="   +
                        resultOfWait  +   ", getSize()="   +  
                        fifo . getSize ());
             }

             for   (   int  i  =   0 ;  i  <   3 ;  i ++   )   {
                 synchronized   (  fifo  )   {
                     Object []  list  =  fifo . removeAll ();
                    print ( "did removeAll(), list.length="   +  
                            list . length );

                     for   (   int  j  =   0 ;  j  <  list . length ;  j ++   )   {
                        print ( "DATA-OUT - list["   +  j  +   "]="   +  
                                list [ j ]);
                     }
                 }
                 Thread . sleep ( 100 );
             }

             for   (   int  i  =   0 ;  i  <   3 ;  i ++   )   {
                 synchronized   (  fifo  )   {
                     Object []  list  =  fifo . removeAtLeastOne ();
                    print (
                         "did removeAtLeastOne(), list.length="   +
                        list . length );

                     for   (   int  j  =   0 ;  j  <  list . length ;  j ++   )   {
                        print ( "DATA-OUT - list["   +  j  +   "]="   +  
                                list [ j ]);
                     }
                 }
                 Thread . sleep ( 1000 );
             }

             while   (   ! fifo . isEmpty ()   )   {
                 synchronized   (  fifo  )   {
                     Object  obj  =  fifo . remove ();
                    print ( "DATA-OUT - did remove(), obj="   +  obj );
                 }
                 Thread . sleep ( 1000 );
             }

            print ( "leaving consumer()" );
         }   catch   (   InterruptedException  ix  )   {
             return ;
         }
     }

     private   static   void  producer ( ObjectFIFO  fifo )   {
         try   {
            print ( "just entered producer()" );
             int  count  =   0 ;

             Object  obj0  =   new   Integer ( count );
            count ++ ;
             synchronized   (  fifo  )   {
                fifo . add ( obj0 );
                print ( "DATA-IN - did add(), obj0="   +  obj0 );

                 boolean  resultOfWait  =  fifo . waitUntilEmpty ( 500 );
                print ( "did waitUntilEmpty(500), resultOfWait="   +
                        resultOfWait  +   ", getSize()="   +  
                        fifo . getSize ());
             }

             for   (   int  i  =   0 ;  i  <   10 ;  i ++   )   {
                 Object  obj  =   new   Integer ( count );
                count ++ ;
                 synchronized   (  fifo  )   {
                    fifo . add ( obj );
                    print ( "DATA-IN - did add(), obj="   +  obj );
                 }
                 Thread . sleep ( 1000 );
             }

             Thread . sleep ( 2000 );

             Object  obj  =   new   Integer ( count );
            count ++ ;
             synchronized   (  fifo  )   {
                fifo . add ( obj );
                print ( "DATA-IN - did add(), obj="   +  obj );
             }
             Thread . sleep ( 500 );

             Integer []  list1  =   new   Integer [ 3 ];
             for   (   int  i  =   0 ;  i  <  list1 . length ;  i ++   )   {
                list1 [ i ]   =   new   Integer ( count );
                count ++ ;
             }

             synchronized   (  fifo  )   {
                fifo . addEach ( list1 );
                print ( "did addEach(), list1.length="   +  
                        list1 . length );
             }

             Integer []  list2  =   new   Integer [ 8 ];
             for   (   int  i  =   0 ;  i  <  list2 . length ;  i ++   )   {
                list2 [ i ]   =   new   Integer ( count );
                count ++ ;
             }

             synchronized   (  fifo  )   {
                fifo . addEach ( list2 );
                print ( "did addEach(), list2.length="   +  
                        list2 . length );
             }

             synchronized   (  fifo  )   {
                fifo . waitUntilEmpty ();
                print ( "fifo.isEmpty()="   +  fifo . isEmpty ());
             }

            print ( "leaving producer()" );
         }   catch   (   InterruptedException  ix  )   {
             return ;
         }
     }

     private   static   synchronized   void  print ( String  msg )   {
         System . out . println (
             Thread . currentThread (). getName ()   +   ": "   +  msg );
     }

     public   static   void  main ( String []  args )   {
         final   ObjectFIFO  fifo  =   new   ObjectFIFO ( 5 );

         Runnable  fullCheckRunnable  =   new   Runnable ()   {
                 public   void  run ()   {
                    fullCheck ( fifo );
                 }
             };

         Thread  fullCheckThread  =  
                 new   Thread ( fullCheckRunnable ,   "fchk" );
        fullCheckThread . setPriority ( 9 );
        fullCheckThread . setDaemon ( true );   // die automatically
        fullCheckThread . start ();

         Runnable  emptyCheckRunnable  =   new   Runnable ()   {
                 public   void  run ()   {
                    emptyCheck ( fifo );
                 }
             };

         Thread  emptyCheckThread  =  
                 new   Thread ( emptyCheckRunnable ,   "echk" );
        emptyCheckThread . setPriority ( 8 );
        emptyCheckThread . setDaemon ( true );   // die automatically
        emptyCheckThread . start ();

         Runnable  consumerRunnable  =   new   Runnable ()   {
                 public   void  run ()   {
                    consumer ( fifo );
                 }
             };

         Thread  consumerThread  =  
                 new   Thread ( consumerRunnable ,   "cons" );
        consumerThread . setPriority ( 7 );
        consumerThread . start ();

         Runnable  producerRunnable  =   new   Runnable ()   {
                 public   void  run ()   {
                    producer ( fifo );
                 }
             };

         Thread  producerThread  =  
                 new   Thread ( producerRunnable ,   "prod" );
        producerThread . setPriority ( 6 );
        producerThread . start ();
     }
}

source/chapter18/SimpleObjectFIFO.java

source/chapter18/SimpleObjectFIFO.java

public   class   SimpleObjectFIFO   extends   Object   {
     private   Object []  queue ;
     private   int  capacity ;
     private   int  size ;
     private   int  head ;
     private   int  tail ;

     public   SimpleObjectFIFO ( int  cap )   {
        capacity  =   (  cap  >   0   )   ?  cap  :   1 ;   // at least 1
        queue  =   new   Object [ capacity ];
        head  =   0 ;
        tail  =   0 ;
        size  =   0 ;
     }

     public   synchronized   int  getSize ()   {
         return  size ;
     }

     public   synchronized   boolean  isFull ()   {
         return   (  size  ==  capacity  );
     }

     public   synchronized   void  add ( Object  obj )   throws   InterruptedException   {
         while   (  isFull ()   )   {
            wait ();
         }

        queue [ head ]   =  obj ;
        head  =   (  head  +   1   )   %  capacity ;
        size ++ ;

        notifyAll ();   // let any waiting threads know about change
     }

     public   synchronized   Object  remove ()   throws   InterruptedException   {
         while   (  size  ==   0   )   {
            wait ();
         }
        
         Object  obj  =  queue [ tail ];
        queue [ tail ]   =   null ;   // don't block GC by keeping unnecessary reference
        tail  =   (  tail  +   1   )   %  capacity ;
        size -- ;

        notifyAll ();   // let any waiting threads know about change

         return  obj ;
     }

     public   synchronized   void  printState ()   {
         StringBuffer  sb  =   new   StringBuffer ();

        sb . append ( "SimpleObjectFIFO:\n" );
        sb . append ( "       capacity="   +  capacity  +   "\n" );

        sb . append ( "           size="   +  size );
         if   (  isFull ()   )   {
            sb . append ( " - FULL" );
         }   else   if   (  size  ==   0   )   {
            sb . append ( " - EMPTY" );
         }
        sb . append ( "\n" );

        sb . append ( "           head="   +  head  +   "\n" );
        sb . append ( "           tail="   +  tail  +   "\n" );

         for   (   int  i  =   0 ;  i  <  queue . length ;  i ++   )   {
            sb . append ( "       queue["   +  i  +   "]="   +  queue [ i ]   +   "\n" );
         }

         System . out . print ( sb );
     }
}

source/chapter18/SimpleObjectFIFOTest.java

source/chapter18/SimpleObjectFIFOTest.java

public   class   SimpleObjectFIFOTest   extends   Object   {
     public   static   void  main ( String []  args )   {
         try   {
             SimpleObjectFIFO  fifo  =   new   SimpleObjectFIFO ( 5 );
            fifo . printState ();
    
            fifo . add ( "S01" );
            fifo . printState ();
    
            fifo . add ( "S02" );
            fifo . printState ();
    
            fifo . add ( "S03" );
            fifo . printState ();
    
             Object  obj  =  fifo . remove ();
             System . out . println ( "just removed obj="   +  obj );
            fifo . printState ();
    
            fifo . add ( "S04" );
            fifo . printState ();
    
            fifo . add ( "S05" );
            fifo . printState ();
    
            fifo . add ( "S06" );
            fifo . printState ();
         }   catch   (   InterruptedException  x  )   {
            x . printStackTrace ();
         }
     }
}
root
source.tar.gz

source.tar

source/chapter02/TwoThread.java

source/chapter02/TwoThread.java

public   class   TwoThread   extends   Thread   {
     public   void  run ()   {
         for   (   int  i  =   0 ;  i  <   10 ;  i ++   )   {
             System . out . println ( "New thread" );
         }
     }

     public   static   void  main ( String []  args )   {
         TwoThread  tt  =   new   TwoThread ();
        tt . start ();

         for   (   int  i  =   0 ;  i  <   10 ;  i ++   )   {
             System . out . println ( "Main thread" );
         }
     }
}

source/chapter03/TwoThread.java

source/chapter03/TwoThread.java

public   class   TwoThread   extends   Thread   {
     private   Thread  creatorThread ;

     public   TwoThread ()   {
         // make a note of the thread that constructed me!
        creatorThread  =   Thread . currentThread ();
     }

     public   void  run ()   {
         for   (   int  i  =   0 ;  i  <   10 ;  i ++   )   {
            printMsg ();
         }
     }

     public   void  printMsg ()   {
         // get a reference to the thread running this
         Thread  t  =   Thread . currentThread ();

         if   (  t  ==  creatorThread  )   {
             System . out . println ( "Creator thread" );
         }   else   if   (  t  ==   this   )   {
             System . out . println ( "New thread" );
         }   else   {
             System . out . println ( "Mystery thread --unexpected!" );
         }
     }

     public   static   void  main ( String []  args )   {
         TwoThread  tt  =   new   TwoThread ();
        tt . start ();

         for   (   int  i  =   0 ;  i  <   10 ;  i ++   )   {
            tt . printMsg ();
         }
     }
}

source/chapter03/TwoThreadAlive.java

source/chapter03/TwoThreadAlive.java

public   class   TwoThreadAlive   extends   Thread   {
     public   void  run ()   {
         for   (   int  i  =   0 ;  i  <   10 ;  i ++   )   {
            printMsg ();
         }
     }

     public   void  printMsg ()   {
         // get a reference to the thread running this
         Thread  t  =   Thread . currentThread ();
         String  name  =  t . getName ();
         System . out . println ( "name="   +  name );
     }

     public   static   void  main ( String []  args )   {
         TwoThreadAlive  tt  =   new   TwoThreadAlive ();
        tt . setName ( "my worker thread" );

         System . out . println ( "before start(), tt.isAlive()="   +  tt . isAlive ());
        tt . start ();
         System . out . println ( "just after start(), tt.isAlive()="   +  tt . isAlive ());

         for   (   int  i  =   0 ;  i  <   10 ;  i ++   )   {
            tt . printMsg ();
         }

         System . out . println (
             "at the end of main(), tt.isAlive()="   +  tt . isAlive ());
     }
}

source/chapter03/TwoThreadGetName.java

source/chapter03/TwoThreadGetName.java

public   class   TwoThreadGetName   extends   Thread   {
     public   void  run ()   {
         for   (   int  i  =   0 ;  i  <   10 ;  i ++   )   {
            printMsg ();
         }
     }

     public   void  printMsg ()   {
         // get a reference to the thread running this
         Thread  t  =   Thread . currentThread ();
         String  name  =  t . getName ();
         System . out . println ( "name="   +  name );
     }

     public   static   void  main ( String []  args )   {
         TwoThreadGetName  tt  =   new   TwoThreadGetName ();
        tt . start ();

         for   (   int  i  =   0 ;  i  <   10 ;  i ++   )   {
            tt . printMsg ();
         }
     }
}

source/chapter03/TwoThreadSetName.java

source/chapter03/TwoThreadSetName.java

public   class   TwoThreadSetName   extends   Thread   {
     public   void  run ()   {
         for   (   int  i  =   0 ;  i  <   10 ;  i ++   )   {
            printMsg ();
         }
     }

     public   void  printMsg ()   {
         // get a reference to the thread running this
         Thread  t  =   Thread . currentThread ();
         String  name  =  t . getName ();
         System . out . println ( "name="   +  name );
     }

     public   static   void  main ( String []  args )   {
         TwoThreadSetName  tt  =   new   TwoThreadSetName ();
        tt . setName ( "my worker thread" );
        tt . start ();

         for   (   int  i  =   0 ;  i  <   10 ;  i ++   )   {
            tt . printMsg ();
         }
     }
}

source/chapter03/TwoThreadSleep.java

source/chapter03/TwoThreadSleep.java

public   class   TwoThreadSleep   extends   Thread   {
     public   void  run ()   {
        loop ();
     }

     public   void  loop ()   {
         // get a reference to the thread running this
         Thread  t  =   Thread . currentThread ();
         String  name  =  t . getName ();

         System . out . println ( "just entered loop() - "   +  name );

         for   (   int  i  =   0 ;  i  <   10 ;  i ++   )   {
             try   {
                 Thread . sleep ( 200 );
             }   catch   (   InterruptedException  x  )   {
                 // ignore
             }

             System . out . println ( "name="   +  name );
         }

         System . out . println ( "about to leave loop() - "   +  name );
     }

     public   static   void  main ( String []  args )   {
         TwoThreadSleep  tt  =   new   TwoThreadSleep ();
        tt . setName ( "my worker thread" );
        tt . start ();

         // pause for a bit
         try   {
             Thread . sleep ( 700 );
         }   catch   (   InterruptedException  x  )   {
             // ignore
         }

        tt . loop ();
     }
}

source/chapter04/SecondCounter.java

source/chapter04/SecondCounter.java

import  java . awt . * ;
import  javax . swing . * ;
import  java . text . * ;

public   class   SecondCounter   extends   JComponent   implements   Runnable   {
     private   volatile   boolean  keepRunning ;
     private   Font  paintFont ;
     private   volatile   String  timeMsg ;
     private   volatile   int  arcLen ;

     public   SecondCounter ()   {
        paintFont  =   new   Font ( "SansSerif" ,   Font . BOLD ,   14 );
        timeMsg  =   "never started" ;
        arcLen  =   0 ;
     }

     public   void  run ()   {
        runClock ();
     }

     public   void  runClock ()   {
         DecimalFormat  fmt  =   new   DecimalFormat ( "0.000" );
         long  normalSleepTime  =   100 ;
         long  nextSleepTime  =  normalSleepTime ;

         int  counter  =   0 ;
         long  startTime  =   System . currentTimeMillis ();
        keepRunning  =   true ;

         while   (  keepRunning  )   {
             try   {
                 Thread . sleep ( nextSleepTime );
             }   catch   (   InterruptedException  x  )   {
                 // ignore
             }

            counter ++ ;
             double  counterSecs  =  counter  /   10.0 ;
             double  elapsedSecs  =  
                 (   System . currentTimeMillis ()   -  startTime  )   /   1000.0 ;

             double  diffSecs  =  counterSecs  -  elapsedSecs ;

            nextSleepTime  =  normalSleepTime  +  
                     (   (   long   )   (  diffSecs  *   1000.0   )   );

             if   (  nextSleepTime  <   0   )   {
                nextSleepTime  =   0 ;
             }

            timeMsg  =  fmt . format ( counterSecs )   +   " - "   +  
                    fmt . format ( elapsedSecs )   +   " = "   +
                    fmt . format ( diffSecs );

            arcLen  =   (   (   (   int   )  counterSecs  )   %   60   )   *   360   /   60 ;
            repaint ();
         }
     }

     public   void  stopClock ()   {
        keepRunning  =   false ;
     }

     public   void  paint ( Graphics  g )   {
        g . setColor ( Color . black );
        g . setFont ( paintFont );
        g . drawString ( timeMsg ,   0 ,   15 );

        g . fillOval ( 0 ,   20 ,   100 ,   100 );    // black border

        g . setColor ( Color . white );
        g . fillOval ( 3 ,   23 ,   94 ,   94 );    // white for unused portion

        g . setColor ( Color . blue );    // blue for used portion
        g . fillArc ( 2 ,   22 ,   96 ,   96 ,   90 ,   - arcLen );
     }
}

source/chapter04/SecondCounterInaccurate.java

source/chapter04/SecondCounterInaccurate.java

import  java . awt . * ;
import  javax . swing . * ;
import  java . text . * ;

public   class   SecondCounterInaccurate   extends   JComponent   implements   Runnable   {
     private   volatile   boolean  keepRunning ;
     private   Font  paintFont ;
     private   volatile   String  timeMsg ;
     private   volatile   int  arcLen ;

     public   SecondCounterInaccurate ()   {
        paintFont  =   new   Font ( "SansSerif" ,   Font . BOLD ,   14 );
        timeMsg  =   "never started" ;
        arcLen  =   0 ;
     }

     public   void  run ()   {
        runClock ();
     }

     public   void  runClock ()   {
         DecimalFormat  fmt  =   new   DecimalFormat ( "0.000" );
         long  normalSleepTime  =   100 ;

         int  counter  =   0 ;
         long  startTime  =   System . currentTimeMillis ();
        keepRunning  =   true ;

         while   (  keepRunning  )   {
             try   {
                 Thread . sleep ( normalSleepTime );
             }   catch   (   InterruptedException  x  )   {
                 // ignore
             }

            counter ++ ;
             double  counterSecs  =  counter  /   10.0 ;
             double  elapsedSecs  =  
                 (   System . currentTimeMillis ()   -  startTime  )   /   1000.0 ;

             double  diffSecs  =  counterSecs  -  elapsedSecs ;

            timeMsg  =  fmt . format ( counterSecs )   +   " - "   +  
                    fmt . format ( elapsedSecs )   +   " = "   +
                    fmt . format ( diffSecs );

            arcLen  =   (   (   (   int   )  counterSecs  )   %   60   )   *   360   /   60 ;
            repaint ();
         }
     }

     public   void  stopClock ()   {
        keepRunning  =   false ;
     }

     public   void  paint ( Graphics  g )   {
        g . setColor ( Color . black );
        g . setFont ( paintFont );
        g . drawString ( timeMsg ,   0 ,   15 );

        g . fillOval ( 0 ,   20 ,   100 ,   100 );    // black border

        g . setColor ( Color . white );
        g . fillOval ( 3 ,   23 ,   94 ,   94 );    // white for unused portion

        g . setColor ( Color . blue );    // blue for used portion
        g . fillArc ( 2 ,   22 ,   96 ,   96 ,   90 ,   - arcLen );
     }
}

source/chapter04/SecondCounterInaccurateMain.java

source/chapter04/SecondCounterInaccurateMain.java

import  java . awt . * ;
import  java . awt . event . * ;
import  javax . swing . * ;
import  javax . swing . border . * ;

public   class   SecondCounterInaccurateMain   extends   JPanel   {
     private   SecondCounterInaccurate  sc ;
     private   JButton  startB ;
     private   JButton  stopB ;

     public   SecondCounterInaccurateMain ()   {
        sc  =   new   SecondCounterInaccurate ();
        startB  =   new   JButton ( "Start" );
        stopB  =   new   JButton ( "Stop" );

        stopB . setEnabled ( false );    // begin with this disabled

        startB . addActionListener ( new   ActionListener ()   {
                 public   void  actionPerformed ( ActionEvent  e )   {
                     // disable to stop more "start" requests
                    startB . setEnabled ( false );

                     // Create and start a new thread to run the counter
                     Thread  counterThread  =   new   Thread ( sc ,   "SecondCounter" );
                    counterThread . start ();

                    stopB . setEnabled ( true );
                    stopB . requestFocus ();
                 }
             });

        stopB . addActionListener ( new   ActionListener ()   {
                 public   void  actionPerformed ( ActionEvent  e )   {
                    stopB . setEnabled ( false );
                    sc . stopClock ();
                    startB . setEnabled ( true );
                    startB . requestFocus ();
                 }
             });

         JPanel  innerButtonP  =   new   JPanel ();
        innerButtonP . setLayout ( new   GridLayout ( 0 ,   1 ,   0 ,   3 ));
        innerButtonP . add ( startB );
        innerButtonP . add ( stopB );

         JPanel  buttonP  =   new   JPanel ();
        buttonP . setLayout ( new   BorderLayout ());
        buttonP . add ( innerButtonP ,   BorderLayout . NORTH );

         this . setLayout ( new   BorderLayout ( 10 ,   10 ));
         this . setBorder ( new   EmptyBorder ( 20 ,   20 ,   20 ,   20 ));
         this . add ( buttonP ,   BorderLayout . WEST );
         this . add ( sc ,   BorderLayout . CENTER );
     }

     public   static   void  main ( String []  args )   {
         SecondCounterInaccurateMain  scm  =   new   SecondCounterInaccurateMain ();

         JFrame  f  =   new   JFrame ( "Second Counter Inaccurate" );
        f . setContentPane ( scm );
        f . setSize ( 320 ,   200 );
        f . setVisible ( true );
        f . addWindowListener ( new   WindowAdapter ()   {
                 public   void  windowClosing ( WindowEvent  e )   {
                     System . exit ( 0 );
                 }
             });
     }
}

source/chapter04/SecondCounterLockup.java

source/chapter04/SecondCounterLockup.java

import  java . awt . * ;
import  javax . swing . * ;
import  java . text . * ;

public   class   SecondCounterLockup   extends   JComponent   {
     private   boolean  keepRunning ;
     private   Font  paintFont ;
     private   String  timeMsg ;
     private   int  arcLen ;

     public   SecondCounterLockup ()   {
        paintFont  =   new   Font ( "SansSerif" ,   Font . BOLD ,   14 );
        timeMsg  =   "never started" ;
        arcLen  =   0 ;
     }

     public   void  runClock ()   {
         System . out . println ( "thread running runClock() is "   +
                 Thread . currentThread (). getName ());

         DecimalFormat  fmt  =   new   DecimalFormat ( "0.000" );
         long  normalSleepTime  =   100 ;

         int  counter  =   0 ;
        keepRunning  =   true ;

         while   (  keepRunning  )   {
             try   {
                 Thread . sleep ( normalSleepTime );
             }   catch   (   InterruptedException  x  )   {
                 // ignore
             }

            counter ++ ;
             double  counterSecs  =  counter  /   10.0 ;

            timeMsg  =  fmt . format ( counterSecs );

            arcLen  =   (   (   (   int   )  counterSecs  )   %   60   )   *   360   /   60 ;
            repaint ();
         }
     }

     public   void  stopClock ()   {
        keepRunning  =   false ;
     }

     public   void  paint ( Graphics  g )   {
         System . out . println ( "thread that invoked paint() is "   +
                 Thread . currentThread (). getName ());

        g . setColor ( Color . black );
        g . setFont ( paintFont );
        g . drawString ( timeMsg ,   0 ,   15 );

        g . fillOval ( 0 ,   20 ,   100 ,   100 );    // black border

        g . setColor ( Color . white );
        g . fillOval ( 3 ,   23 ,   94 ,   94 );    // white for unused portion

        g . setColor ( Color . blue );    // blue for used portion
        g . fillArc ( 2 ,   22 ,   96 ,   96 ,   90 ,   - arcLen );
     }
}

source/chapter04/SecondCounterLockupMain.java

source/chapter04/SecondCounterLockupMain.java

import  java . awt . * ;
import  java . awt . event . * ;
import  javax . swing . * ;
import  javax . swing . border . * ;

public   class   SecondCounterLockupMain   extends   JPanel   {
     private   SecondCounterLockup  sc ;
     private   JButton  startB ;
     private   JButton  stopB ;

     public   SecondCounterLockupMain ()   {
        sc  =   new   SecondCounterLockup ();
        startB  =   new   JButton ( "Start" );
        stopB  =   new   JButton ( "Stop" );

        stopB . setEnabled ( false );    // begin with this disabled

        startB . addActionListener ( new   ActionListener ()   {
                 public   void  actionPerformed ( ActionEvent  e )   {
                     // disable to stop more "start" requests
                    startB . setEnabled ( false );

                     // Run the counter --watch out big trouble here!
                    sc . runClock ();

                    stopB . setEnabled ( true );
                    stopB . requestFocus ();
                 }
             });

        stopB . addActionListener ( new   ActionListener ()   {
                 public   void  actionPerformed ( ActionEvent  e )   {
                    stopB . setEnabled ( false );
                    sc . stopClock ();
                    startB . setEnabled ( true );
                    startB . requestFocus ();
                 }
             });

         JPanel  innerButtonP  =   new   JPanel ();
        innerButtonP . setLayout ( new   GridLayout ( 0 ,   1 ,   0 ,   3 ));
        innerButtonP . add ( startB );
        innerButtonP . add ( stopB );

         JPanel  buttonP  =   new   JPanel ();
        buttonP . setLayout ( new   BorderLayout ());
        buttonP . add ( innerButtonP ,   BorderLayout . NORTH );

         this . setLayout ( new   BorderLayout ( 10 ,   10 ));
         this . setBorder ( new   EmptyBorder ( 20 ,   20 ,   20 ,   20 ));
         this . add ( buttonP ,   BorderLayout . WEST );
         this . add ( sc ,   BorderLayout . CENTER );
     }

     public   static   void  main ( String []  args )   {
         SecondCounterLockupMain  scm  =   new   SecondCounterLockupMain ();

         JFrame  f  =   new   JFrame ( "Second Counter Lockup" );
        f . setContentPane ( scm );
        f . setSize ( 320 ,   200 );
        f . setVisible ( true );
        f . addWindowListener ( new   WindowAdapter ()   {
                 public   void  windowClosing ( WindowEvent  e )   {
                     System . exit ( 0 );
                 }
             });
     }
}

source/chapter04/SecondCounterMain.java

source/chapter04/SecondCounterMain.java

import  java . awt . * ;
import  java . awt . event . * ;
import  javax . swing . * ;
import  javax . swing . border . * ;

public   class   SecondCounterMain   extends   JPanel   {
     private   SecondCounter  sc ;
     private   JButton  startB ;
     private   JButton  stopB ;

     public   SecondCounterMain ()   {
        sc  =   new   SecondCounter ();
        startB  =   new   JButton ( "Start" );
        stopB  =   new   JButton ( "Stop" );

        stopB . setEnabled ( false );    // begin with this disabled

        startB . addActionListener ( new   ActionListener ()   {
                 public   void  actionPerformed ( ActionEvent  e )   {
                     // disable to stop more "start" requests
                    startB . setEnabled ( false );

                     // Create and start a new thread to run the counter
                     Thread  counterThread  =   new   Thread ( sc ,   "SecondCounter" );
                    counterThread . start ();

                    stopB . setEnabled ( true );
                    stopB . requestFocus ();
                 }
             });

        stopB . addActionListener ( new   ActionListener ()   {
                 public   void  actionPerformed ( ActionEvent  e )   {
                    stopB . setEnabled ( false );
                    sc . stopClock ();
                    startB . setEnabled ( true );
                    startB . requestFocus ();
                 }
             });

         JPanel  innerButtonP  =   new   JPanel ();
        innerButtonP . setLayout ( new   GridLayout ( 0 ,   1 ,   0 ,   3 ));
        innerButtonP . add ( startB );
        innerButtonP . add ( stopB );

         JPanel  buttonP  =   new   JPanel ();
        buttonP . setLayout ( new   BorderLayout ());
        buttonP . add ( innerButtonP ,   BorderLayout . NORTH );

         this . setLayout ( new   BorderLayout ( 10 ,   10 ));
         this . setBorder ( new   EmptyBorder ( 20 ,   20 ,   20 ,   20 ));
         this . add ( buttonP ,   BorderLayout . WEST );
         this . add ( sc ,   BorderLayout . CENTER );
     }

     public   static   void  main ( String []  args )   {
         SecondCounterMain  scm  =   new   SecondCounterMain ();

         JFrame  f  =   new   JFrame ( "Second Counter" );
        f . setContentPane ( scm );
        f . setSize ( 320 ,   200 );
        f . setVisible ( true );
        f . addWindowListener ( new   WindowAdapter ()   {
                 public   void  windowClosing ( WindowEvent  e )   {
                     System . exit ( 0 );
                 }
             });
     }
}

source/chapter04/SecondCounterRunnable.java

source/chapter04/SecondCounterRunnable.java

import  java . awt . * ;
import  javax . swing . * ;
import  java . text . * ;

public   class   SecondCounterRunnable   extends   JComponent   implements   Runnable   {
     private   volatile   boolean  keepRunning ;
     private   Font  paintFont ;
     private   volatile   String  timeMsg ;
     private   volatile   int  arcLen ;

     public   SecondCounterRunnable ()   {
        paintFont  =   new   Font ( "SansSerif" ,   Font . BOLD ,   14 );
        timeMsg  =   "never started" ;
        arcLen  =   0 ;
     }

     public   void  run ()   {
        runClock ();
     }

     public   void  runClock ()   {
         DecimalFormat  fmt  =   new   DecimalFormat ( "0.000" );
         long  normalSleepTime  =   100 ;

         int  counter  =   0 ;
        keepRunning  =   true ;

         while   (  keepRunning  )   {
             try   {
                 Thread . sleep ( normalSleepTime );
             }   catch   (   InterruptedException  x  )   {
                 // ignore
             }

            counter ++ ;
             double  counterSecs  =  counter  /   10.0 ;

            timeMsg  =  fmt . format ( counterSecs );

            arcLen  =   (   (   (   int   )  counterSecs  )   %   60   )   *   360   /   60 ;
            repaint ();
         }
     }

     public   void  stopClock ()   {
        keepRunning  =   false ;
     }

     public   void  paint ( Graphics  g )   {
        g . setColor ( Color . black );
        g . setFont ( paintFont );
        g . drawString ( timeMsg ,   0 ,   15 );

        g . fillOval ( 0 ,   20 ,   100 ,   100 );    // black border

        g . setColor ( Color . white );
        g . fillOval ( 3 ,   23 ,   94 ,   94 );    // white for unused portion

        g . setColor ( Color . blue );    // blue for used portion
        g . fillArc ( 2 ,   22 ,   96 ,   96 ,   90 ,   - arcLen );
     }
}

source/chapter04/SecondCounterRunnableMain.java

source/chapter04/SecondCounterRunnableMain.java

import  java . awt . * ;
import  java . awt . event . * ;
import  javax . swing . * ;
import  javax . swing . border . * ;

public   class   SecondCounterRunnableMain   extends   JPanel   {
     private   SecondCounterRunnable  sc ;
     private   JButton  startB ;
     private   JButton  stopB ;

     public   SecondCounterRunnableMain ()   {
        sc  =   new   SecondCounterRunnable ();
        startB  =   new   JButton ( "Start" );
        stopB  =   new   JButton ( "Stop" );

        stopB . setEnabled ( false );    // begin with this disabled

        startB . addActionListener ( new   ActionListener ()   {
                 public   void  actionPerformed ( ActionEvent  e )   {
                     // disable to stop more "start" requests
                    startB . setEnabled ( false );

                     // Create and start a new thread to run the counter
                     Thread  counterThread  =   new   Thread ( sc ,   "SecondCounter" );
                    counterThread . start ();

                    stopB . setEnabled ( true );
                    stopB . requestFocus ();
                 }
             });

        stopB . addActionListener ( new   ActionListener ()   {
                 public   void  actionPerformed ( ActionEvent  e )   {
                    stopB . setEnabled ( false );
                    sc . stopClock ();
                    startB . setEnabled ( true );
                    startB . requestFocus ();
                 }
             });

         JPanel  innerButtonP  =   new   JPanel ();
        innerButtonP . setLayout ( new   GridLayout ( 0 ,   1 ,   0 ,   3 ));
        innerButtonP . add ( startB );
        innerButtonP . add ( stopB );

         JPanel  buttonP  =   new   JPanel ();
        buttonP . setLayout ( new   BorderLayout ());
        buttonP . add ( innerButtonP ,   BorderLayout . NORTH );

         this . setLayout ( new   BorderLayout ( 10 ,   10 ));
         this . setBorder ( new   EmptyBorder ( 20 ,   20 ,   20 ,   20 ));
         this . add ( buttonP ,   BorderLayout . WEST );
         this . add ( sc ,   BorderLayout . CENTER );
     }

     public   static   void  main ( String []  args )   {
         SecondCounterRunnableMain  scm  =   new   SecondCounterRunnableMain ();

         JFrame  f  =   new   JFrame ( "Second Counter Runnable" );
        f . setContentPane ( scm );
        f . setSize ( 320 ,   200 );
        f . setVisible ( true );
        f . addWindowListener ( new   WindowAdapter ()   {
                 public   void  windowClosing ( WindowEvent  e )   {
                     System . exit ( 0 );
                 }
             });
     }
}

source/chapter05/AlternateStop.java

source/chapter05/AlternateStop.java

public   class   AlternateStop   extends   Object   implements   Runnable   {
     private   volatile   boolean  stopRequested ;
     private   Thread  runThread ;

     public   void  run ()   {
        runThread  =   Thread . currentThread ();
        stopRequested  =   false ;

         int  count  =   0 ;

         while   (   ! stopRequested  )   {
             System . out . println ( "Running ... count="   +  count );
            count ++ ;

             try   {
                 Thread . sleep ( 300 );
             }   catch   (   InterruptedException  x  )   {
                 Thread . currentThread (). interrupt ();   // re-assert interrupt
             }
         }
     }

     public   void  stopRequest ()   {
        stopRequested  =   true ;

         if   (  runThread  !=   null   )   {
            runThread . interrupt ();
         }
     }

     public   static   void  main ( String []  args )   {
         AlternateStop  as  =   new   AlternateStop ();
         Thread  t  =   new   Thread ( as );
        t . start ();

         try   {
             Thread . sleep ( 2000 );
         }   catch   (   InterruptedException  x  )   {
             // ignore
         }

        as . stopRequest ();
     }
}

source/chapter05/AlternateSuspendResume.java

source/chapter05/AlternateSuspendResume.java

public   class   AlternateSuspendResume  
         extends   Object  
         implements   Runnable   {

     private   volatile   int  firstVal ;
     private   volatile   int  secondVal ;
     private   volatile   boolean  suspended ;

     public   boolean  areValuesEqual ()   {
         return   (  firstVal  ==  secondVal  );
     }

     public   void  run ()   {
         try   {
            suspended  =   false ;
            firstVal  =   0 ;
            secondVal  =   0 ;
            workMethod ();
         }   catch   (   InterruptedException  x  )   {
             System . out . println (
                 "interrupted while in workMethod()" );
         }
     }

     private   void  workMethod ()   throws   InterruptedException   {
         int  val  =   1 ;

         while   (   true   )   {
             // blocks only if suspended is true
            waitWhileSuspended ();  

            stepOne ( val );
            stepTwo ( val );
            val ++ ;

             // blocks only if suspended is true
            waitWhileSuspended ();  

             Thread . sleep ( 200 );    // pause before looping again
         }
     }

     private   void  stepOne ( int  newVal )  
                     throws   InterruptedException   {

        firstVal  =  newVal ;

         // simulate some other lengthy process
         Thread . sleep ( 300 );   
     }

     private   void  stepTwo ( int  newVal )   {
        secondVal  =  newVal ;
     }

     public   void  suspendRequest ()   {
        suspended  =   true ;
     }

     public   void  resumeRequest ()   {
        suspended  =   false ;
     }

     private   void  waitWhileSuspended ()  
                 throws   InterruptedException   {

         // This is an example of a "busy wait" technique.  It is
         // not the best way to wait for a condition to change 
         // because it continually requires some processor 
         // cycles to perform the checks.  A better technique 
         // is to use Java's built-in wait-notify mechanism.
         while   (  suspended  )   {
             Thread . sleep ( 200 );
         }
     }

     public   static   void  main ( String []  args )   {
         AlternateSuspendResume  asr  =  
                 new   AlternateSuspendResume ();

         Thread  t  =   new   Thread ( asr );
        t . start ();

         // let the other thread get going and run for a while
         try   {   Thread . sleep ( 1000 );   }  
         catch   (   InterruptedException  x  )   {   }

         for   (   int  i  =   0 ;  i  <   10 ;  i ++   )   {
            asr . suspendRequest ();

             // Give the thread a chance to notice the 
             // suspension request.
             try   {   Thread . sleep ( 350 );   }  
             catch   (   InterruptedException  x  )   {   }

             System . out . println ( "dsr.areValuesEqual()="   +  
                    asr . areValuesEqual ());

            asr . resumeRequest ();

             try   {  
                 // Pause for a random amount of time 
                 // between 0 and 2 seconds.
                 Thread . sleep (
                         (   long   )   ( Math . random ()   *   2000.0 )   );
             }   catch   (   InterruptedException  x  )   {
                 // ignore
             }
         }

         System . exit ( 0 );   // abruptly terminate application
     }
}

source/chapter05/BestReplacement.java

source/chapter05/BestReplacement.java

// uses BooleanLock from chapter 17

public   class   BestReplacement   extends   Object   {
     private   Thread  internalThread ;
     private   volatile   boolean  stopRequested ;

     private   BooleanLock  suspendRequested ;
     private   BooleanLock  internalThreadSuspended ;

     public   BestReplacement ()   {
        stopRequested  =   false ;

        suspendRequested  =   new   BooleanLock ( false );
        internalThreadSuspended  =   new   BooleanLock ( false );

         Runnable  r  =   new   Runnable ()   {
                 public   void  run ()   {
                     try   {
                        runWork ();
                     }   catch   (   Exception  x  )   {
                         // in case ANY exception slips through
                        x . printStackTrace ();  
                     }
                 }
             };

        internalThread  =   new   Thread ( r );
        internalThread . start ();
     }

     private   void  runWork ()   {
         int  count  =   0 ;

         while   (   ! stopRequested  )   {
             try   {
                waitWhileSuspended ();
             }   catch   (   InterruptedException  x  )   {
                 // Reassert interrupt so that remaining code
                 // sees that an interrupt has been requested.
                 Thread . currentThread (). interrupt ();  

                 // Reevaluate while condition --probably 
                 // false now.
                 continue ;
             }

             System . out . println ( "Part I - count="   +  count );

             try   {
                 Thread . sleep ( 1000 );
             }   catch   (   InterruptedException  x  )   {
                 Thread . currentThread (). interrupt ();   // reassert
                 // continue on as if sleep completed normally
             }

             System . out . println ( "Part II - count="   +  count );

             try   {
                 Thread . sleep ( 1000 );
             }   catch   (   InterruptedException  x  )   {
                 Thread . currentThread (). interrupt ();   // reassert
                 // continue on as if sleep completed normally
             }

             System . out . println ( "Part III - count="   +  count );

            count ++ ;
         }
     }

     private   void  waitWhileSuspended ()  
                     throws   InterruptedException   {

         // only called by the internal thread - private method

         synchronized   (  suspendRequested  )   {
             if   (  suspendRequested . isTrue ()   )   {
                 try   {
                    internalThreadSuspended . setValue ( true );
                    suspendRequested . waitUntilFalse ( 0 );  
                 }   finally   {
                    internalThreadSuspended . setValue ( false );
                 }
             }
         }
     }

     public   void  suspendRequest ()   {
        suspendRequested . setValue ( true );
     }

     public   void  resumeRequest ()   {
        suspendRequested . setValue ( false );
     }

     public   boolean  waitForActualSuspension ( long  msTimeout )  
                     throws   InterruptedException   {

         // Returns 'true' if suspended, 'false' if the 
         // timeout expired.

         return  internalThreadSuspended . waitUntilTrue ( msTimeout );
     }

     public   void  stopRequest ()   {
        stopRequested  =   true ;
        internalThread . interrupt ();
     }

     public   boolean  isAlive ()   {
         return  internalThread . isAlive ();
     }

     public   static   void  main ( String []  args )   {
         try   {
             BestReplacement  br  =   new   BestReplacement ();
             System . out . println (
                     "--> just created, br.isAlive()="   +  
                    br . isAlive ());
             Thread . sleep ( 4200 );

             long  startTime  =   System . currentTimeMillis ();
            br . suspendRequest ();
             System . out . println (
                     "--> just submitted a suspendRequest" );

             boolean  suspensionTookEffect  =  
                    br . waitForActualSuspension ( 10000 );
             long  stopTime  =   System . currentTimeMillis ();

             if   (  suspensionTookEffect  )   {
                 System . out . println (
                     "--> the internal thread took "   +
                     ( stopTime  -  startTime )   +   " ms to notice "   +
                     "\n    the suspend request and is now "   +
                     "suspended." );
             }   else   {
                 System . out . println (
                     "--> the internal thread did not notice "   +
                     "the suspend request "   +
                     "\n    within 10 seconds." );
             }

             Thread . sleep ( 5000 );

            br . resumeRequest ();
             System . out . println (
                     "--> just submitted a resumeRequest" );
             Thread . sleep ( 2200 );

            br . stopRequest ();
             System . out . println (
                     "--> just submitted a stopRequest" );
         }   catch   (   InterruptedException  x  )   {
             // ignore
         }
     }
}

source/chapter05/BooleanLock.java

source/chapter05/BooleanLock.java

public   class   BooleanLock   extends   Object   {
     private   boolean  value ;

     public   BooleanLock ( boolean  initialValue )   {
        value  =  initialValue ;
     }

     public   BooleanLock ()   {
         this ( false );
     }

     public   synchronized   void  setValue ( boolean  newValue )   {
         if   (  newValue  !=  value  )   {
            value  =  newValue ;
            notifyAll ();
         }
     }

     public   synchronized   boolean  waitToSetTrue ( long  msTimeout )  
             throws   InterruptedException   {

         boolean  success  =  waitUntilFalse ( msTimeout );
         if   (  success  )   {
            setValue ( true );
         }

         return  success ;
     }

     public   synchronized   boolean  waitToSetFalse ( long  msTimeout )  
             throws   InterruptedException   {

         boolean  success  =  waitUntilTrue ( msTimeout );
         if   (  success  )   {
            setValue ( false );
         }

         return  success ;
     }

     public   synchronized   boolean  isTrue ()   {
         return  value ;
     }

     public   synchronized   boolean  isFalse ()   {
         return   ! value ;
     }

     public   synchronized   boolean  waitUntilTrue ( long  msTimeout )  
             throws   InterruptedException   {

         return  waitUntilStateIs ( true ,  msTimeout );
     }

     public   synchronized   boolean  waitUntilFalse ( long  msTimeout )  
             throws   InterruptedException   {

         return  waitUntilStateIs ( false ,  msTimeout );
     }

     public   synchronized   boolean  waitUntilStateIs (
                 boolean  state ,  
                 long  msTimeout
             )   throws   InterruptedException   {

         if   (  msTimeout  ==   0L   )   {
             while   (  value  !=  state  )   {
                wait ();    // wait indefinitely until notified
             }

             // condition has finally been met
             return   true ;
         }  

         // only wait for the specified amount of time
         long  endTime  =   System . currentTimeMillis ()   +  msTimeout ;
         long  msRemaining  =  msTimeout ;

         while   (   (  value  !=  state  )   &&   (  msRemaining  >   0L   )   )   {
            wait ( msRemaining );
            msRemaining  =  endTime  -   System . currentTimeMillis ();
         }

         // May have timed out, or may have met value, 
         // calculate return value.
         return   (  value  ==  state  );
     }
}

source/chapter05/DaemonThread.java

source/chapter05/DaemonThread.java

public   class   DaemonThread   extends   Object   implements   Runnable   {
     public   void  run ()   {
         System . out . println ( "entering run()" );

         try   {
             System . out . println ( "in run() - currentThread()="   +  
                     Thread . currentThread ());

             while   (   true   )   {
                 try   {   Thread . sleep ( 500 );   }  
                 catch   (   InterruptedException  x  )   {}

                 System . out . println ( "in run() - woke up again" );
             }
         }   finally   {
             System . out . println ( "leaving run()" );
         }
     }
}

source/chapter05/DaemonThreadMain.java

source/chapter05/DaemonThreadMain.java

public   class   DaemonThreadMain   extends   Object   {
     public   static   void  main ( String []  args )   {
         System . out . println ( "entering main()" );

         Thread  t  =   new   Thread ( new   DaemonThread ());
        t . setDaemon ( true );
        t . start ();

         try   {   Thread . sleep ( 3000 );   }   catch   (   InterruptedException  x  )   {   }

         System . out . println ( "leaving main()" );
     }
}

source/chapter05/DeprecatedStop.java

source/chapter05/DeprecatedStop.java

public   class   DeprecatedStop   extends   Object   implements   Runnable   {

     public   void  run ()   {
         int  count  =   0 ;

         while   (   true   )   {
             System . out . println ( "Running ... count="   +  count );
            count ++ ;

             try   {
                 Thread . sleep ( 300 );
             }   catch   (   InterruptedException  x  )   {
                 // ignore
             }
         }
     }


     public   static   void  main ( String []  args )   {
         DeprecatedStop  ds  =   new   DeprecatedStop ();
         Thread  t  =   new   Thread ( ds );
        t . start ();

         try   {
             Thread . sleep ( 2000 );
         }   catch   (   InterruptedException  x  )   {
             // ignore
         }

         // Abruptly stop the other thread in its tracks!
        t . stop ();
     }
}

source/chapter05/DeprecatedSuspendResume.java

source/chapter05/DeprecatedSuspendResume.java

public   class   DeprecatedSuspendResume  
         extends   Object  
         implements   Runnable   {

     private   volatile   int  firstVal ;
     private   volatile   int  secondVal ;

     public   boolean  areValuesEqual ()   {
         return   (  firstVal  ==  secondVal  );
     }

     public   void  run ()   {
         try   {
            firstVal  =   0 ;
            secondVal  =   0 ;
            workMethod ();
         }   catch   (   InterruptedException  x  )   {
             System . out . println (
                     "interrupted while in workMethod()" );
         }
     }

     private   void  workMethod ()   throws   InterruptedException   {
         int  val  =   1 ;

         while   (   true   )   {
            stepOne ( val );
            stepTwo ( val );
            val ++ ;

             Thread . sleep ( 200 );    // pause before looping again
         }
     }

     private   void  stepOne ( int  newVal )  
             throws   InterruptedException   {

        firstVal  =  newVal ;
         Thread . sleep ( 300 );    // simulate some other long process
     }

     private   void  stepTwo ( int  newVal )   {
        secondVal  =  newVal ;
     }

     public   static   void  main ( String []  args )   {
         DeprecatedSuspendResume  dsr  =  
                 new   DeprecatedSuspendResume ();
         Thread  t  =   new   Thread ( dsr );
        t . start ();

         // let the other thread get going and run for a while
         try   {   Thread . sleep ( 1000 );   }  
         catch   (   InterruptedException  x  )   {   }

         for   (   int  i  =   0 ;  i  <   10 ;  i ++   )   {
            t . suspend ();
             System . out . println ( "dsr.areValuesEqual()="   +  
                                dsr . areValuesEqual ());
            t . resume ();
             try   {  
                 // Pause for a random amount of time 
                 // between 0 and 2 seconds.
                 Thread . sleep (  
                         (   long   )   ( Math . random ()   *   2000.0 )   );
             }   catch   (   InterruptedException  x  )   {
                 // ignore
             }
         }

         System . exit ( 0 );   // abruptly terminate application
     }
}

source/chapter05/GeneralInterrupt.java

source/chapter05/GeneralInterrupt.java

public   class   GeneralInterrupt   extends   Object   implements   Runnable   {
     public   void  run ()   {
         /*
        try {
            System.out.println("in run() - about to sleep for 20 seconds");
            work();
            System.out.println("in run() - woke up");
        } catch ( InterruptedException x ) {
            System.out.println("in run() - interrupted while sleeping");
            //return;
        }
        */

         try   {
             System . out . println ( "in run() - about to work2()" );
            work2 ();
             System . out . println ( "in run() - back from  work2()" );
         }   catch   (   InterruptedException  x  )   {
             System . out . println ( "in run() - interrupted in work2()" );
             return ;
         }

         System . out . println ( "in run() - doing stuff after nap" );
         System . out . println ( "in run() - leaving normally" );
     }

     public   void  work2 ()   throws   InterruptedException   {
         while   (   true   )   {
             if   (   Thread . currentThread (). isInterrupted ()   )   {
                 System . out . println ( "C isInterrupted()="   +  
                     Thread . currentThread (). isInterrupted ());
                 Thread . sleep ( 2000 );
                 System . out . println ( "D isInterrupted()="   +  
                     Thread . currentThread (). isInterrupted ());
             }
         }
     }

     public   void  work ()   throws   InterruptedException   {
         while   (   true   )   {
             for   (   int  i  =   0 ;  i  <   100000 ;  i ++   )   {
                 int  j  =  i  *   2 ;
             }

             System . out . println ( "A isInterrupted()="   +  
                 Thread . currentThread (). isInterrupted ());

             if   (   Thread . interrupted ()   )   {
                 System . out . println ( "B isInterrupted()="   +  
                     Thread . currentThread (). isInterrupted ());
                 throw   new   InterruptedException ();
             }
         }
     }


     public   static   void  main ( String []  args )   {
         GeneralInterrupt  si  =   new   GeneralInterrupt ();
         Thread  t  =   new   Thread ( si );
        t . start ();

         // be sure that the new thread gets a chance to run for a while
         try   {   Thread . sleep ( 2000 );   }   catch   (   InterruptedException  x  )   {   }

         System . out . println ( "in main() - interrupting other thread" );
        t . interrupt ();
         System . out . println ( "in main() - leaving" );
     }
}

source/chapter05/InterruptCheck.java

source/chapter05/InterruptCheck.java

public   class   InterruptCheck   extends   Object   {
     public   static   void  main ( String []  args )   {
         Thread  t  =   Thread . currentThread ();
         System . out . println ( "Point A: t.isInterrupted()="   +  t . isInterrupted ());
        t . interrupt ();
         System . out . println ( "Point B: t.isInterrupted()="   +  t . isInterrupted ());
         System . out . println ( "Point C: t.isInterrupted()="   +  t . isInterrupted ());

         try   {
             Thread . sleep ( 2000 );
             System . out . println ( "was NOT interrupted" );
         }   catch   (   InterruptedException  x  )   {
             System . out . println ( "was interrupted" );
         }

         System . out . println ( "Point D: t.isInterrupted()="   +  t . isInterrupted ());
     }
}

source/chapter05/InterruptReset.java

source/chapter05/InterruptReset.java

public   class   InterruptReset   extends   Object   {
     public   static   void  main ( String []  args )   {
         System . out . println (
             "Point X: Thread.interrupted()="   +   Thread . interrupted ());
         Thread . currentThread (). interrupt ();
         System . out . println (
             "Point Y: Thread.interrupted()="   +   Thread . interrupted ());
         System . out . println (
             "Point Z: Thread.interrupted()="   +   Thread . interrupted ());
     }
}

source/chapter05/PendingInterrupt.java

source/chapter05/PendingInterrupt.java

public   class   PendingInterrupt   extends   Object   {
     public   static   void  main ( String []  args )   {
         if   (  args . length  >   0   )   {
             Thread . currentThread (). interrupt ();
         }  

         long  startTime  =   System . currentTimeMillis ();
         try   {
             Thread . sleep ( 2000 );
             System . out . println ( "was NOT interrupted" );
         }   catch   (   InterruptedException  x  )   {
             System . out . println ( "was interrupted" );
         }

         System . out . println (
                 "elapsedTime="   +   (   System . currentTimeMillis ()   -  startTime  ));
     }
}

source/chapter05/PiInterrupt.java

source/chapter05/PiInterrupt.java

public   class   PiInterrupt   extends   Object   implements   Runnable   {
     private   double  latestPiEstimate ;

     public   void  run ()   {
         try   {
             System . out . println ( "for comparison, Math.PI="   +  
                                 Math . PI );
            calcPi ( 0.000000001 );
             System . out . println ( "within accuracy, latest pi="   +  
                                latestPiEstimate );
         }   catch   (   InterruptedException  x  )   {
             System . out . println ( "INTERRUPTED!! latest pi="   +  
                                latestPiEstimate );
         }
     }

     private   void  calcPi ( double  accuracy )  
                 throws   InterruptedException   {

        latestPiEstimate  =   0.0 ;
         long  iteration  =   0 ;
         int  sign  =   - 1 ;

         while   (   Math . abs ( latestPiEstimate  -   Math . PI )   >  
                accuracy  )   {

             if   (   Thread . interrupted ()   )   {
                 throw   new   InterruptedException ();
             }

            iteration ++ ;
            sign  =   - sign ;
            latestPiEstimate  +=  
                    sign  *   4.0   /   (   (   2   *  iteration  )   -   1   );
         }
     }

     public   static   void  main ( String []  args )   {
         PiInterrupt  pi  =   new   PiInterrupt ();
         Thread  t  =   new   Thread ( pi );
        t . start ();

         try   {
             Thread . sleep ( 10000 );
            t . interrupt ();
         }   catch   (   InterruptedException  x  )   {
             // ignore
         }
     }
}

source/chapter05/SleepInterrupt.java

source/chapter05/SleepInterrupt.java

public   class   SleepInterrupt   extends   Object   implements   Runnable   {
     public   void  run ()   {
         try   {
             System . out . println (
                     "in run() - about to sleep for 20 seconds" );
             Thread . sleep ( 20000 );
             System . out . println ( "in run() - woke up" );
         }   catch   (   InterruptedException  x  )   {
             System . out . println (
                     "in run() - interrupted while sleeping" );
             return ;
         }

         System . out . println ( "in run() - doing stuff after nap" );
         System . out . println ( "in run() - leaving normally" );
     }


     public   static   void  main ( String []  args )   {
         SleepInterrupt  si  =   new   SleepInterrupt ();
         Thread  t  =   new   Thread ( si );
        t . start ();

         // Be sure that the new thread gets a chance to 
         // run for a while.
         try   {   Thread . sleep ( 2000 );   }  
         catch   (   InterruptedException  x  )   {   }

         System . out . println (
                 "in main() - interrupting other thread" );
        t . interrupt ();
         System . out . println ( "in main() - leaving" );
     }
}

source/chapter05/VisualSuspendResume.java

source/chapter05/VisualSuspendResume.java

import  java . awt . * ;
import  java . awt . event . * ;
import  javax . swing . * ;

public   class   VisualSuspendResume  
             extends   JPanel  
             implements   Runnable   {

     private   static   final   String []  symbolList  =  
             {   "|" ,   "/" ,   "-" ,   "\\" ,   "|" ,   "/" ,   "-" ,   "\\"   };

     private   Thread  runThread ;
     private   JTextField  symbolTF ;

     public   VisualSuspendResume ()   {
        symbolTF  =   new   JTextField ();  
        symbolTF . setEditable ( false );
        symbolTF . setFont ( new   Font ( "Monospaced" ,   Font . BOLD ,   26 ));
        symbolTF . setHorizontalAlignment ( JTextField . CENTER );

         final   JButton  suspendB  =   new   JButton ( "Suspend" );
         final   JButton  resumeB  =   new   JButton ( "Resume" );

        suspendB . addActionListener ( new   ActionListener ()   {
                 public   void  actionPerformed ( ActionEvent  e )   {
                    suspendNow ();
                 }
             });

        resumeB . addActionListener ( new   ActionListener ()   {
                 public   void  actionPerformed ( ActionEvent  e )   {
                    resumeNow ();
                 }
             });
        
         JPanel  innerStackP  =   new   JPanel ();
        innerStackP . setLayout ( new   GridLayout ( 0 ,   1 ,   3 ,   3 ));
        innerStackP . add ( symbolTF );
        innerStackP . add ( suspendB );
        innerStackP . add ( resumeB );

         this . setLayout ( new   FlowLayout ( FlowLayout . CENTER ));
         this . add ( innerStackP );
     }

     private   void  suspendNow ()   {
         if   (  runThread  !=   null   )   {   // avoid NullPointerException
            runThread . suspend ();
         }
     }

     private   void  resumeNow ()   {
         if   (  runThread  !=   null   )   {   // avoid NullPointerException
            runThread . resume ();
         }
     }

     public   void  run ()   {
         try   {
             // Store this for the suspendNow() and 
             // resumeNow() methods to use.
            runThread  =   Thread . currentThread ();
             int  count  =   0 ;

             while   (   true   )   {
                 // each time through, show the next symbol
                symbolTF . setText (
                    symbolList [  count  %  symbolList . length  ]);
                 Thread . sleep ( 200 );
                count ++ ;
             }
         }   catch   (   InterruptedException  x  )   {
             // ignore
         }   finally   {
             // The thread is about to die, make sure that the 
             // reference to it is also lost.
            runThread  =   null ;
         }
     }

     public   static   void  main ( String []  args )   {
         VisualSuspendResume  vsr  =   new   VisualSuspendResume ();
         Thread  t  =   new   Thread ( vsr );
        t . start ();

         JFrame  f  =   new   JFrame ( "Visual Suspend Resume" );
        f . setContentPane ( vsr );
        f . setSize ( 320 ,   200 );
        f . setVisible ( true );
        f . addWindowListener ( new   WindowAdapter ()   {
                 public   void  windowClosing ( WindowEvent  e )   {
                     System . exit ( 0 );
                 }
             });
     }
}

source/chapter06/GetPriority.java

source/chapter06/GetPriority.java

public   class   GetPriority   extends   Object   {
     private   static   Runnable  makeRunnable ()   {
         Runnable  r  =    new   Runnable ()   {
                 public   void  run ()   {
                     for   (   int  i  =   0 ;  i  <   5 ;  i ++   )   {
                         Thread  t  =   Thread . currentThread ();
                         System . out . println (
                             "in run() - priority="   +  
                            t . getPriority ()   +
                             ", name="   +  t . getName ());

                         try   {
                             Thread . sleep ( 2000 );
                         }   catch   (   InterruptedException  x  )   {
                             // ignore
                         }
                     }
                 }
             };

         return  r ;
     }

     public   static   void  main ( String []  args )   {
         System . out . println (
             "in main() - Thread.currentThread().getPriority()="   +
             Thread . currentThread (). getPriority ());

         System . out . println (
             "in main() - Thread.currentThread().getName()="   +
             Thread . currentThread (). getName ());

         Thread  threadA  =   new   Thread ( makeRunnable (),   "threadA" );
        threadA . start ();

         try   {   Thread . sleep ( 3000 );   }  
         catch   (   InterruptedException  x  )   {   }

         System . out . println ( "in main() - threadA.getPriority()="   +
                threadA . getPriority ());
     }
}

source/chapter06/PriorityCompete.java

source/chapter06/PriorityCompete.java

public   class   PriorityCompete   extends   Object   {
     private   volatile   int  count ;
     private   boolean  yield ;
     private   Thread  internalThread ;
     private   volatile   boolean  noStopRequested ;

     public   PriorityCompete (
                 String  name ,  
                 int  priority ,  
                 boolean  yield
             )   {

        count  =   0 ;
         this . yield  =  yield ;

        noStopRequested  =   true ;
         Runnable  r  =   new   Runnable ()   {
                 public   void  run ()   {
                     try   {
                        runWork ();
                     }   catch   (   Exception  x  )   {
                         // in case ANY exception slips through
                        x . printStackTrace ();  
                     }
                 }
             };

        internalThread  =   new   Thread ( r ,  name );
        internalThread . setPriority ( priority );
     }

     private   void  runWork ()   {
         Thread . yield ();

         while   (  noStopRequested  )   {
             if   (  yield  )   {
                 Thread . yield ();
             }

            count ++ ;

             for   (   int  i  =   0 ;  i  <   1000 ;  i ++   )   {
                 double  x  =  i  *   Math . PI  /   Math . E ;
             }
         }
     }

     public   void  startRequest ()   {
        internalThread . start ();
     }

     public   void  stopRequest ()   {
        noStopRequested  =   false ;
     }

     public   int  getCount ()   {
         return  count ;
     }

     public   String  getNameAndPriority ()   {
         return  internalThread . getName ()   +  
             ": priority="   +  internalThread . getPriority ();
     }

     private   static   void  runSet ( boolean  yield )   {
         PriorityCompete []  pc  =   new   PriorityCompete [ 3 ];
        pc [ 0 ]   =   new   PriorityCompete ( "PC0" ,   3 ,  yield );
        pc [ 1 ]   =   new   PriorityCompete ( "PC1" ,   6 ,  yield );
        pc [ 2 ]   =   new   PriorityCompete ( "PC2" ,   6 ,  yield );

         // let the dust settle for a bit before starting them up
         try   {   Thread . sleep ( 1000 );   }  
         catch   (   InterruptedException  x  )   {   }

         for   (   int  i  =   0 ;  i  <  pc . length ;  i ++   )   {
            pc [ i ]. startRequest ();
         }

         long  startTime  =   System . currentTimeMillis ();
         try   {   Thread . sleep ( 10000 );   }  
         catch   (   InterruptedException  x  )   {   }

         for   (   int  i  =   0 ;  i  <  pc . length ;  i ++   )   {
            pc [ i ]. stopRequest ();
         }

         long  stopTime  =   System . currentTimeMillis ();

         // let things settle down again
         try   {   Thread . sleep ( 1000 );   }  
         catch   (   InterruptedException  x  )   {   }

         int  totalCount  =   0 ;
         for   (   int  i  =   0 ;  i  <  pc . length ;  i ++   )   {
            totalCount  +=  pc [ i ]. getCount ();
         }

         System . out . println ( "totalCount="   +  totalCount  +
             ", count/ms="   +  roundTo ((( double )  totalCount )   /  
                                     ( stopTime  -  startTime ),   3 ));

         for   (   int  i  =   0 ;  i  <  pc . length ;  i ++   )   {
             double  perc  =  roundTo ( 100.0   *  pc [ i ]. getCount ()   /  
                                    totalCount ,   2 );
             System . out . println ( pc [ i ]. getNameAndPriority ()   +  
                 ", "   +  perc  +   "%, count="   +  pc [ i ]. getCount ());
         }
     }

     public   static   double  roundTo ( double  val ,   int  places )   {
         double  factor  =   Math . pow ( 10 ,  places );
         return   (   ( int )   (   (  val  *  factor  )   +   0.5   )   )   /  factor ;
     }

     public   static   void  main ( String []  args )   {
         Runnable  r  =   new   Runnable ()   {
                 public   void  run ()   {
                     System . out . println (
                             "Run without using yield()" );
                     System . out . println (
                             "=========================" );
                    runSet ( false );

                     System . out . println ();
                     System . out . println ( "Run using yield()" );
                     System . out . println ( "=================" );
                    runSet ( true );
                 }
             };

         Thread  t  =   new   Thread ( r ,   "PriorityCompete" );
        t . setPriority ( Thread . MAX_PRIORITY  -   1 );
        t . start ();
     }
}

source/chapter06/SetPriority.java

source/chapter06/SetPriority.java

public   class   SetPriority   extends   Object   {
     private   static   Runnable  makeRunnable ()   {
         Runnable  r  =    new   Runnable ()   {
                 public   void  run ()   {
                     for   (   int  i  =   0 ;  i  <   5 ;  i ++   )   {
                         Thread  t  =   Thread . currentThread ();
                         System . out . println (
                             "in run() - priority="   +  
                            t . getPriority ()   +
                             ", name="   +  t . getName ());

                         try   {
                             Thread . sleep ( 2000 );
                         }   catch   (   InterruptedException  x  )   {
                             // ignore
                         }
                     }
                 }
             };

         return  r ;
     }

     public   static   void  main ( String []  args )   {
         Thread  threadA  =   new   Thread ( makeRunnable (),   "threadA" );
        threadA . setPriority ( 8 );
        threadA . start ();

         Thread  threadB  =   new   Thread ( makeRunnable (),   "threadB" );
        threadB . setPriority ( 2 );
        threadB . start ();

         Runnable  r  =   new   Runnable ()   {
                 public   void  run ()   {
                     Thread  threadC  =  
                         new   Thread ( makeRunnable (),   "threadC" );
                    threadC . start ();
                 }
             };
         Thread  threadD  =   new   Thread ( r ,   "threadD" );
        threadD . setPriority ( 7 );
        threadD . start ();

         try   {   Thread . sleep ( 3000 );   }  
         catch   (   InterruptedException  x  )   {   }

        threadA . setPriority ( 3 );
         System . out . println ( "in main() - threadA.getPriority()="   +
                threadA . getPriority ());
     }
}

source/chapter07/BothInMethod.java

source/chapter07/BothInMethod.java

public   class   BothInMethod   extends   Object   {
     private   String  objID ;

     public   BothInMethod ( String  objID )   {
         this . objID  =  objID ;
     }

     public   void  doStuff ( int  val )   {
        print ( "entering doStuff()" );
         int  num  =  val  *   2   +  objID . length ();
        print ( "in doStuff() - local variable num="   +  num );

         // slow things down to make observations
         try   {   Thread . sleep ( 2000 );   }   catch   (   InterruptedException  x  )   {   }

        print ( "leaving doStuff()" );
     }

     public   void  print ( String  msg )   {
        threadPrint ( "objID="   +  objID  +   " - "   +  msg );
     }

     public   static   void  threadPrint ( String  msg )   {
         String  threadName  =   Thread . currentThread (). getName ();
         System . out . println ( threadName  +   ": "   +  msg );
     }

     public   static   void  main ( String []  args )   {
         final   BothInMethod  bim  =   new   BothInMethod ( "obj1" );

         Runnable  runA  =   new   Runnable ()   {
                 public   void  run ()   {
                    bim . doStuff ( 3 );
                 }
             };

         Thread  threadA  =   new   Thread ( runA ,   "threadA" );
        threadA . start ();

         try   {   Thread . sleep ( 200 );   }   catch   (   InterruptedException  x  )   {   }

         Runnable  runB  =   new   Runnable ()   {
                 public   void  run ()   {
                    bim . doStuff ( 7 );
                 }
             };

         Thread  threadB  =   new   Thread ( runB ,   "threadB" );
        threadB . start ();
     }
}

source/chapter07/CleanRead.java

source/chapter07/CleanRead.java

public   class   CleanRead   extends   Object   {
     private   String  fname ;
     private   String  lname ;

     public   synchronized   String  getNames ()   {
         return  lname  +   ", "   +  fname ;
     }

     public   synchronized   void  setNames (
                 String  firstName ,  
                 String  lastName
             )   {

        print ( "entering setNames()" );
        fname  =  firstName ;

         try   {   Thread . sleep ( 1000 );   }  
         catch   (   InterruptedException  x  )   {   }

        lname  =  lastName ;
        print ( "leaving setNames() - "   +  lname  +   ", "   +  fname );
     }

     public   static   void  print ( String  msg )   {
         String  threadName  =   Thread . currentThread (). getName ();
         System . out . println ( threadName  +   ": "   +  msg );
     }

     public   static   void  main ( String []  args )   {
         final   CleanRead  cr  =   new   CleanRead ();
        cr . setNames ( "George" ,   "Washington" );   // initially

         Runnable  runA  =   new   Runnable ()   {
                 public   void  run ()   {
                    cr . setNames ( "Abe" ,   "Lincoln" );
                 }
             };

         Thread  threadA  =   new   Thread ( runA ,   "threadA" );
        threadA . start ();

         try   {   Thread . sleep ( 200 );   }  
         catch   (   InterruptedException  x  )   {   }

         Runnable  runB  =   new   Runnable ()   {
                 public   void  run ()   {
                    print ( "getNames()="   +  cr . getNames ());
                 }
             };

         Thread  threadB  =   new   Thread ( runB ,   "threadB" );
        threadB . start ();
     }
}

source/chapter07/CorruptWrite.java

source/chapter07/CorruptWrite.java

public   class   CorruptWrite   extends   Object   {
     private   String  fname ;
     private   String  lname ;

     public   void  setNames ( String  firstName ,   String  lastName )   {
        print ( "entering setNames()" );
        fname  =  firstName ;

         // A thread might be swapped out here, and may stay 
         // out for a varying amount of time. The different 
         // sleep times exaggerate this.
         if   (  fname . length ()   <   5   )   {
             try   {   Thread . sleep ( 1000 );   }  
             catch   (   InterruptedException  x  )   {   }
         }   else   {
             try   {   Thread . sleep ( 2000 );   }  
             catch   (   InterruptedException  x  )   {   }
         }

        lname  =  lastName ;

        print ( "leaving setNames() - "   +  lname  +   ", "   +  fname );
     }

     public   static   void  print ( String  msg )   {
         String  threadName  =   Thread . currentThread (). getName ();
         System . out . println ( threadName  +   ": "   +  msg );
     }

     public   static   void  main ( String []  args )   {
         final   CorruptWrite  cw  =   new   CorruptWrite ();

         Runnable  runA  =   new   Runnable ()   {
                 public   void  run ()   {
                    cw . setNames ( "George" ,   "Washington" );
                 }
             };

         Thread  threadA  =   new   Thread ( runA ,   "threadA" );
        threadA . start ();

         try   {   Thread . sleep ( 200 );   }  
         catch   (   InterruptedException  x  )   {   }

         Runnable  runB  =   new   Runnable ()   {
                 public   void  run ()   {
                    cw . setNames ( "Abe" ,   "Lincoln" );
                 }
             };

         Thread  threadB  =   new   Thread ( runB ,   "threadB" );
        threadB . start ();
     }
}

source/chapter07/Deadlock.java

source/chapter07/Deadlock.java

public   class   Deadlock   extends   Object   {
     private   String  objID ;

     public   Deadlock ( String  id )   {
        objID  =  id ;
     }

     public   synchronized   void  checkOther ( Deadlock  other )   {
        print ( "entering checkOther()" );

         // simulate some lengthy process
         try   {   Thread . sleep ( 2000 );   }  
         catch   (   InterruptedException  x  )   {   }

        print ( "in checkOther() - about to "   +
                 "invoke 'other.action()'" );
        other . action ();

        print ( "leaving checkOther()" );
     }

     public   synchronized   void  action ()   {
        print ( "entering action()" );

         // simulate some work here
         try   {   Thread . sleep ( 500 );   }  
         catch   (   InterruptedException  x  )   {   }

        print ( "leaving action()" );
     }

     public   void  print ( String  msg )   {
        threadPrint ( "objID="   +  objID  +   " - "   +  msg );
     }

     public   static   void  threadPrint ( String  msg )   {
         String  threadName  =   Thread . currentThread (). getName ();
         System . out . println ( threadName  +   ": "   +  msg );
     }

     public   static   void  main ( String []  args )   {
         final   Deadlock  obj1  =   new   Deadlock ( "obj1" );
         final   Deadlock  obj2  =   new   Deadlock ( "obj2" );

         Runnable  runA  =   new   Runnable ()   {
                 public   void  run ()   {
                    obj1 . checkOther ( obj2 );
                 }
             };

         Thread  threadA  =   new   Thread ( runA ,   "threadA" );
        threadA . start ();

         try   {   Thread . sleep ( 200 );   }  
         catch   (   InterruptedException  x  )   {   }

         Runnable  runB  =   new   Runnable ()   {
                 public   void  run ()   {
                    obj2 . checkOther ( obj1 );
                 }
             };

         Thread  threadB  =   new   Thread ( runB ,   "threadB" );
        threadB . start ();

         try   {   Thread . sleep ( 5000 );   }  
         catch   (   InterruptedException  x  )   {   }

        threadPrint ( "finished sleeping" );

        threadPrint ( "about to interrupt() threadA" );
        threadA . interrupt ();

         try   {   Thread . sleep ( 1000 );   }  
         catch   (   InterruptedException  x  )   {   }

        threadPrint ( "about to interrupt() threadB" );
        threadB . interrupt ();

         try   {   Thread . sleep ( 1000 );   }  
         catch   (   InterruptedException  x  )   {   }

        threadPrint ( "did that break the deadlock?" );
     }
}

source/chapter07/DirtyRead.java

source/chapter07/DirtyRead.java

public   class   DirtyRead   extends   Object   {
     private   String  fname ;
     private   String  lname ;

     public   String  getNames ()   {
         return  lname  +   ", "   +  fname ;
     }

     public   synchronized   void  setNames (
                 String  firstName ,  
                 String  lastName
             )   {

        print ( "entering setNames()" );
        fname  =  firstName ;

         try   {   Thread . sleep ( 1000 );   }  
         catch   (   InterruptedException  x  )   {   }

        lname  =  lastName ;
        print ( "leaving setNames() - "   +  lname  +   ", "   +  fname );
     }

     public   static   void  print ( String  msg )   {
         String  threadName  =   Thread . currentThread (). getName ();
         System . out . println ( threadName  +   ": "   +  msg );
     }

     public   static   void  main ( String []  args )   {
         final   DirtyRead  dr  =   new   DirtyRead ();
        dr . setNames ( "George" ,   "Washington" );   // initially 

         Runnable  runA  =   new   Runnable ()   {
                 public   void  run ()   {
                    dr . setNames ( "Abe" ,   "Lincoln" );
                 }
             };

         Thread  threadA  =   new   Thread ( runA ,   "threadA" );
        threadA . start ();

         try   {   Thread . sleep ( 200 );   }  
         catch   (   InterruptedException  x  )   {   }

         Runnable  runB  =   new   Runnable ()   {
                 public   void  run ()   {
                    print ( "getNames()="   +  dr . getNames ());
                 }
             };

         Thread  threadB  =   new   Thread ( runB ,   "threadB" );
        threadB . start ();
     }
}

source/chapter07/FixedWrite.java

source/chapter07/FixedWrite.java

public   class   FixedWrite   extends   Object   {
     private   String  fname ;
     private   String  lname ;

     public   synchronized   void  setNames (
                 String  firstName ,  
                 String  lastName
             )   {

        print ( "entering setNames()" );
        fname  =  firstName ;

         // A thread might be swapped out here, and may stay 
         // out for a varying amount of time. The different 
         // sleep times exaggerate this.
         if   (  fname . length ()   <   5   )   {
             try   {   Thread . sleep ( 1000 );   }  
             catch   (   InterruptedException  x  )   {   }
         }   else   {
             try   {   Thread . sleep ( 2000 );   }  
             catch   (   InterruptedException  x  )   {   }
         }

        lname  =  lastName ;

        print ( "leaving setNames() - "   +  lname  +   ", "   +  fname );
     }

     public   static   void  print ( String  msg )   {
         String  threadName  =   Thread . currentThread (). getName ();
         System . out . println ( threadName  +   ": "   +  msg );
     }

     public   static   void  main ( String []  args )   {
         final   FixedWrite  fw  =   new   FixedWrite ();

         Runnable  runA  =   new   Runnable ()   {
                 public   void  run ()   {
                    fw . setNames ( "George" ,   "Washington" );
                 }
             };

         Thread  threadA  =   new   Thread ( runA ,   "threadA" );
        threadA . start ();

         try   {   Thread . sleep ( 200 );   }  
         catch   (   InterruptedException  x  )   {   }

         Runnable  runB  =   new   Runnable ()   {
                 public   void  run ()   {
                    fw . setNames ( "Abe" ,   "Lincoln" );
                 }
             };

         Thread  threadB  =   new   Thread ( runB ,   "threadB" );
        threadB . start ();
     }
}

source/chapter07/OnlyOneInMethod.java

source/chapter07/OnlyOneInMethod.java

public   class   OnlyOneInMethod   extends   Object   {
     private   String  objID ;

     public   OnlyOneInMethod ( String  objID )   {
         this . objID  =  objID ;
     }

     public   synchronized   void  doStuff ( int  val )   {
        print ( "entering doStuff()" );
         int  num  =  val  *   2   +  objID . length ();
        print ( "in doStuff() - local variable num="   +  num );

         // slow things down to make observations
         try   {   Thread . sleep ( 2000 );   }   catch   (   InterruptedException  x  )   {   }

        print ( "leaving doStuff()" );
     }

     public   void  print ( String  msg )   {
        threadPrint ( "objID="   +  objID  +   " - "   +  msg );
     }

     public   static   void  threadPrint ( String  msg )   {
         String  threadName  =   Thread . currentThread (). getName ();
         System . out . println ( threadName  +   ": "   +  msg );
     }

     public   static   void  main ( String []  args )   {
         final   OnlyOneInMethod  ooim  =   new   OnlyOneInMethod ( "obj1" );

         Runnable  runA  =   new   Runnable ()   {
                 public   void  run ()   {
                    ooim . doStuff ( 3 );
                 }
             };

         Thread  threadA  =   new   Thread ( runA ,   "threadA" );
        threadA . start ();

         try   {   Thread . sleep ( 200 );   }   catch   (   InterruptedException  x  )   {   }

         Runnable  runB  =   new   Runnable ()   {
                 public   void  run ()   {
                    ooim . doStuff ( 7 );
                 }
             };

         Thread  threadB  =   new   Thread ( runB ,   "threadB" );
        threadB . start ();
     }
}

source/chapter07/SafeCollectionIteration.java

source/chapter07/SafeCollectionIteration.java

import  java . util . * ;

public   class   SafeCollectionIteration   extends   Object   {
     public   static   void  main ( String []  args )   {
         // To be safe, only keep a reference to the 
         // *synchronized* list so that you are sure 
         // that all accesses are controlled.

         // The collection *must* be synchronized 
         // (a List in this case).
         List  wordList  =  
                 Collections . synchronizedList ( new   ArrayList ());

        wordList . add ( "Iterators" );
        wordList . add ( "require" );
        wordList . add ( "special" );
        wordList . add ( "handling" );

         // All of this must be in a synchronized block to 
         // block other threads from modifying wordList while 
         // the iteration is in progress.
         synchronized   (  wordList  )   {
             Iterator  iter  =  wordList . iterator ();
             while   (  iter . hasNext ()   )   {
                 String  s  =   ( String )  iter . next ();
                 System . out . println ( "found string: "   +  s  +  
                     ", length="   +  s . length ());
             }
         }
     }
}

source/chapter07/SafeListCopy.java

source/chapter07/SafeListCopy.java

import  java . util . * ;

public   class   SafeListCopy   extends   Object   {
     public   static   void  printWords ( String []  word )   {
         System . out . println ( "word.length="   +  word . length );
         for   (   int  i  =   0 ;  i  <  word . length ;  i ++   )   {
             System . out . println ( "word["   +  i  +   "]="   +  word [ i ]);
         }
     }

     public   static   void  main ( String []  args )   {
         // To be safe, only keep a reference to the 
         // *synchronized* list so that you are sure that 
         // all accesses are controlled.
         List  wordList  =  
                 Collections . synchronizedList ( new   ArrayList ());

        wordList . add ( "Synchronization" );
        wordList . add ( "is" );
        wordList . add ( "important" );

         // First technique (favorite)
         String []  wordA  =  
                 ( String [])  wordList . toArray ( new   String [ 0 ]);

        printWords ( wordA );

         // Second technique
         String []  wordB ;
         synchronized   (  wordList  )   {
             int  size  =  wordList . size ();
            wordB  =   new   String [ size ];
            wordList . toArray ( wordB );
         }

        printWords ( wordB );

         // Third technique (the 'synchronized' *is* necessary)
         String []  wordC ;
         synchronized   (  wordList  )   {
            wordC  =   ( String [])  wordList . toArray (
                                 new   String [ wordList . size ()]);
         }

        printWords ( wordC );
     }
}

source/chapter07/SafeVectorCopy.java

source/chapter07/SafeVectorCopy.java

import  java . util . * ;

public   class   SafeVectorCopy   extends   Object   {
     public   static   void  main ( String []  args )   {
         Vector  vect  =   new   Vector ();
        vect . addElement ( "Synchronization" );
        vect . addElement ( "is" );
        vect . addElement ( "important" );

         String []  word ;

         synchronized   (  vect  )   {
             int  size  =  vect . size ();
            word  =   new   String [ size ];

             for   (   int  i  =   0 ;  i  <  word . length ;  i ++   )   {
                word [ i ]   =   ( String )  vect . elementAt ( i );
             }
         }

         System . out . println ( "word.length="   +  word . length );
         for   (   int  i  =   0 ;  i  <  word . length ;  i ++   )   {
             System . out . println ( "word["   +  i  +   "]="   +  word [ i ]);
         }
     }
}

source/chapter07/StaticBlock.java

source/chapter07/StaticBlock.java

public   class   StaticBlock   extends   Object   {
     public   static   synchronized   void  staticA ()   {
         System . out . println ( "entering staticA()" );

         try   {   Thread . sleep ( 5000 );   }  
         catch   (   InterruptedException  x  )   {   }

         System . out . println ( "leaving staticA()" );
     }

     public   static   void  staticB ()   {
         System . out . println ( "entering staticB()" );

         synchronized   (   StaticBlock . class   )   {
             System . out . println (
                     "in staticB() - inside sync block" );

             try   {   Thread . sleep ( 2000 );   }  
             catch   (   InterruptedException  x  )   {   }
         }

         System . out . println ( "leaving staticB()" );
     }

     public   static   void  main ( String []  args )   {
         Runnable  runA  =   new   Runnable ()   {
                 public   void  run ()   {
                     StaticBlock . staticA ();
                 }
             };

         Thread  threadA  =   new   Thread ( runA ,   "threadA" );
        threadA . start ();

         try   {   Thread . sleep ( 200 );   }  
         catch   (   InterruptedException  x  )   {   }

         Runnable  runB  =   new   Runnable ()   {
                 public   void  run ()   {
                     StaticBlock . staticB ();
                 }
             };

         Thread  threadB  =   new   Thread ( runB ,   "threadB" );
        threadB . start ();
     }
}

source/chapter07/StaticNeedSync.java

source/chapter07/StaticNeedSync.java

public   class   StaticNeedSync   extends   Object   {
     private   static   int  nextSerialNum  =   10001 ;

     public   static   int  getNextSerialNum ()   {
         int  sn  =  nextSerialNum ;

         // Simulate a delay that is possible if the thread 
         // scheduler chooses to swap this thread off the 
         // processor at this point. The delay is exaggerated 
         // for demonstration purposes.
         try   {   Thread . sleep ( 1000 );   }  
         catch   (   InterruptedException  x  )   {   }

        nextSerialNum ++ ;
         return  sn ;
     }

     private   static   void  print ( String  msg )   {
         String  threadName  =   Thread . currentThread (). getName ();
         System . out . println ( threadName  +   ": "   +  msg );
     }

     public   static   void  main ( String []  args )   {
         try   {
             Runnable  r  =   new   Runnable ()   {
                     public   void  run ()   {
                        print ( "getNextSerialNum()="   +  
                                getNextSerialNum ());
                     }
                 };
            
             Thread  threadA  =   new   Thread ( r ,   "threadA" );
            threadA . start ();
    
             Thread . sleep ( 1500 );  
    
             Thread  threadB  =   new   Thread ( r ,   "threadB" );
            threadB . start ();
    
             Thread . sleep ( 500 );  
    
             Thread  threadC  =   new   Thread ( r ,   "threadC" );
            threadC . start ();
    
             Thread . sleep ( 2500 );  

             Thread  threadD  =   new   Thread ( r ,   "threadD" );
            threadD . start ();
         }   catch   (   InterruptedException  x  )   {
             // ignore
         }
     }
}

source/chapter07/StaticSync.java

source/chapter07/StaticSync.java

public   class   StaticSync   extends   Object   {
     private   static   int  nextSerialNum  =   10001 ;

     public   static   synchronized   int  getNextSerialNum ()   {
         int  sn  =  nextSerialNum ;

         // Simulate a delay that is possible if the thread 
         // scheduler chooses to swap this thread off the 
         // processor at this point. The delay is exaggerated 
         // for demonstration purposes.
         try   {   Thread . sleep ( 1000 );   }  
         catch   (   InterruptedException  x  )   {   }

        nextSerialNum ++ ;
         return  sn ;
     }

     private   static   void  print ( String  msg )   {
         String  threadName  =   Thread . currentThread (). getName ();
         System . out . println ( threadName  +   ": "   +  msg );
     }

     public   static   void  main ( String []  args )   {
         try   {
             Runnable  r  =   new   Runnable ()   {
                     public   void  run ()   {
                        print ( "getNextSerialNum()="   +  
                                getNextSerialNum ());
                     }
                 };
            
             Thread  threadA  =   new   Thread ( r ,   "threadA" );
            threadA . start ();
    
             Thread . sleep ( 1500 );  
    
             Thread  threadB  =   new   Thread ( r ,   "threadB" );
            threadB . start ();
    
             Thread . sleep ( 500 );  
    
             Thread  threadC  =   new   Thread ( r ,   "threadC" );
            threadC . start ();
    
             Thread . sleep ( 2500 );  

             Thread  threadD  =   new   Thread ( r ,   "threadD" );
            threadD . start ();
         }   catch   (   InterruptedException  x  )   {
             // ignore
         }
     }
}

source/chapter07/TwoObjects.java

source/chapter07/TwoObjects.java

public   class   TwoObjects   extends   Object   {
     private   String  objID ;

     public   TwoObjects ( String  objID )   {
         this . objID  =  objID ;
     }

     public   synchronized   void  doStuff ( int  val )   {
        print ( "entering doStuff()" );
         int  num  =  val  *   2   +  objID . length ();
        print ( "in doStuff() - local variable num="   +  num );

         // slow things down to make observations
         try   {   Thread . sleep ( 2000 );   }   catch   (   InterruptedException  x  )   {   }

        print ( "leaving doStuff()" );
     }

     public   void  print ( String  msg )   {
        threadPrint ( "objID="   +  objID  +   " - "   +  msg );
     }

     public   static   void  threadPrint ( String  msg )   {
         String  threadName  =   Thread . currentThread (). getName ();
         System . out . println ( threadName  +   ": "   +  msg );
     }

     public   static   void  main ( String []  args )   {
         final   TwoObjects  obj1  =   new   TwoObjects ( "obj1" );
         final   TwoObjects  obj2  =   new   TwoObjects ( "obj2" );

         Runnable  runA  =   new   Runnable ()   {
                 public   void  run ()   {
                    obj1 . doStuff ( 3 );
                 }
             };

         Thread  threadA  =   new   Thread ( runA ,   "threadA" );
        threadA . start ();

         try   {   Thread . sleep ( 200 );   }   catch   (   InterruptedException  x  )   {   }

         Runnable  runB  =   new   Runnable ()   {
                 public   void  run ()   {
                    obj2 . doStuff ( 7 );
                 }
             };

         Thread  threadB  =   new   Thread ( runB ,   "threadB" );
        threadB . start ();
     }
}

source/chapter07/Volatile.java

source/chapter07/Volatile.java

public   class   Volatile   extends   Object   implements   Runnable   {
     // not marked as 'volatile', but it should be!
     private   int  value ;   

     private   volatile   boolean  missedIt ;

     // doesn't need to be volatile-doesn't change
     private   long  creationTime ;  

     public   Volatile ()   {
        value  =   10 ;
        missedIt  =   false ;
        creationTime  =   System . currentTimeMillis ();
     }

     public   void  run ()   {
        print ( "entering run()" );

         // each time, check to see if 'value' is different
         while   (  value  <   20   )   {

             // Used to break out of the loop if change to 
             // value is missed.
             if    (  missedIt  )   {
                 int  currValue  =  value ;

                 // Simply execute a synchronized statement on an
                 // arbitrary object to see the effect.
                 Object  lock  =   new   Object ();
                 synchronized   (  lock  )   {
                     // do nothing!
                 }

                 int  valueAfterSync  =  value ;

                print ( "in run() - see value="   +  currValue  +
                     ", but rumor has it that it changed!" );
                print ( "in run() - valueAfterSync="   +  
                    valueAfterSync );

                 break ;  
             }
         }

        print ( "leaving run()" );
     }

     public   void  workMethod ()   throws   InterruptedException   {
        print ( "entering workMethod()" );

        print ( "in workMethod() - about to sleep for 2 seconds" );
         Thread . sleep ( 2000 );

        value  =   50 ;
        print ( "in workMethod() - just set value="   +  value );

        print ( "in workMethod() - about to sleep for 5 seconds" );
         Thread . sleep ( 5000 );

        missedIt  =   true ;
        print ( "in workMethod() - just set missedIt="   +  missedIt );

        print ( "in workMethod() - about to sleep for 3 seconds" );
         Thread . sleep ( 3000 );

        print ( "leaving workMethod()" );
     }

     private   void  print ( String  msg )   {
         // This method could have been simplified by using 
         // functionality present in the java.text package, 
         // but did not take advantage of it since that package 
         // is not present in JDK1.0.

         long  interval  =   System . currentTimeMillis ()   -  
                        creationTime ;

         String  tmpStr  =   "    "   +   (  interval  /   1000.0   )   +   "000" ;
        
         int  pos  =  tmpStr . indexOf ( "." );
         String  secStr  =  tmpStr . substring ( pos  -   2 ,  pos  +   4 );

         String  nameStr  =   "        "   +  
                 Thread . currentThread (). getName ();

        nameStr  =  nameStr . substring ( nameStr . length ()   -   8 ,  
                                    nameStr . length ());
        
         System . out . println ( secStr  +   " "   +  nameStr  +   ": "   +  msg );
     }

     public   static   void  main ( String []  args )   {
         try   {
             Volatile  vol  =   new   Volatile ();

             // slight pause to let some time elapse
             Thread . sleep ( 100 );   

             Thread  t  =   new   Thread ( vol );
            t . start ();

             // slight pause to allow run() to go first
             Thread . sleep ( 100 );   

            vol . workMethod ();
         }   catch   (   InterruptedException  x  )   {
             System . err . println (
                 "one of the sleeps was interrupted" );
         }
     }
}

source/chapter08/CubbyHole.java

source/chapter08/CubbyHole.java

public   class   CubbyHole   extends   Object   {
     private   Object  slot ;

     public   CubbyHole ()   {
        slot  =   null ;   // null indicates empty
     }

     public   synchronized   void  putIn ( Object  obj )  
                         throws   InterruptedException   {

        print ( "in putIn() - entering" );

         while   (  slot  !=   null   )   {
            print ( "in putIn() - occupied, about to wait()" );
            wait ();   // wait while slot is occupied
            print ( "in putIn() - notified, back from wait()" );
         }

        slot  =  obj ;    // put object into slot
        print ( "in putIn() - filled slot, about to notifyAll()" );
        notifyAll ();   // signal that slot has been filled

        print ( "in putIn() - leaving" );
     }

     public   synchronized   Object  takeOut ()  
                         throws   InterruptedException   {

        print ( "in takeOut() - entering" );

         while   (  slot  ==   null   )   {
            print ( "in takeOut() - empty, about to wait()" );
            wait ();   // wait while slot is empty
            print ( "in takeOut() - notified, back from wait()" );
         }

         Object  obj  =  slot ;
        slot  =   null ;   // mark slot as empty
        print (
             "in takeOut() - emptied slot, about to notifyAll()" );
        notifyAll ();   // signal that slot is empty

        print ( "in takeOut() - leaving" );
         return  obj ;
     }

     private   static   void  print ( String  msg )   {
         String  name  =   Thread . currentThread (). getName ();
         System . out . println ( name  +   ": "   +  msg );
     }
}

source/chapter08/CubbyHoleMain.java

source/chapter08/CubbyHoleMain.java

public   class   CubbyHoleMain   extends   Object   {
     private   static   void  print ( String  msg )   {
         String  name  =   Thread . currentThread (). getName ();
         System . out . println ( name  +   ": "   +  msg );
     }

     public   static   void  main ( String []  args )   {
         final   CubbyHole  ch  =   new   CubbyHole ();

         Runnable  runA  =   new   Runnable ()   {
                 public   void  run ()   {
                     try   {
                         String  str ;
                         Thread . sleep ( 500 );

                        str  =   "multithreaded" ;
                        ch . putIn ( str );
                        print ( "in run() - just put in: '"   +  
                                str  +   "'" );

                        str  =   "programming" ;
                        ch . putIn ( str );
                        print ( "in run() - just put in: '"   +  
                                str  +   "'" );

                        str  =   "with Java" ;
                        ch . putIn ( str );
                        print ( "in run() - just put in: '"   +  
                                str  +   "'" );
                     }   catch   (   InterruptedException  x  )   {
                        x . printStackTrace ();
                     }
                 }
             };

         Runnable  runB  =   new   Runnable ()   {
                 public   void  run ()   {
                     try   {
                         Object  obj ;

                        obj  =  ch . takeOut ();
                        print ( "in run() - just took out: '"   +  
                                obj  +   "'" );

                         Thread . sleep ( 500 );

                        obj  =  ch . takeOut ();
                        print ( "in run() - just took out: '"   +  
                                obj  +   "'" );

                        obj  =  ch . takeOut ();
                        print ( "in run() - just took out: '"   +  
                                obj  +   "'" );
                     }   catch   (   InterruptedException  x  )   {
                        x . printStackTrace ();
                     }
                 }
             };

         Thread  threadA  =   new   Thread ( runA ,   "threadA" );
        threadA . start ();

         Thread  threadB  =   new   Thread ( runB ,   "threadB" );
        threadB . start ();
     }
}

source/chapter08/EarlyNotify.java

source/chapter08/EarlyNotify.java

import  java . util . * ;

public   class   EarlyNotify   extends   Object   {
     private   List  list ;

     public   EarlyNotify ()   {
        list  =   Collections . synchronizedList ( new   LinkedList ());
     }

     public   String  removeItem ()   throws   InterruptedException   {
        print ( "in removeItem() - entering" );

         synchronized   (  list  )   {
             if   (  list . isEmpty ()   )   {    // dangerous to use 'if'!
                print ( "in removeItem() - about to wait()" );
                list . wait ();
                print ( "in removeItem() - done with wait()" );
             }

             // extract the new first item
             String  item  =   ( String )  list . remove ( 0 );

            print ( "in removeItem() - leaving" );
             return  item ;
         }
     }

     public   void  addItem ( String  item )   {
        print ( "in addItem() - entering" );
         synchronized   (  list  )   {
             // There'll always be room to add to this List 
             // because it expands as needed. 
            list . add ( item );
            print ( "in addItem() - just added: '"   +  item  +   "'" );

             // After adding, notify any and all waiting 
             // threads that the list has changed.
            list . notifyAll ();
            print ( "in addItem() - just notified" );
         }
        print ( "in addItem() - leaving" );
     }

     private   static   void  print ( String  msg )   {
         String  name  =   Thread . currentThread (). getName ();
         System . out . println ( name  +   ": "   +  msg );
     }

     public   static   void  main ( String []  args )   {
         final   EarlyNotify  en  =   new   EarlyNotify ();

         Runnable  runA  =   new   Runnable ()   {
                 public   void  run ()   {
                     try   {
                         String  item  =  en . removeItem ();
                        print ( "in run() - returned: '"   +  
                                item  +   "'" );
                     }   catch   (   InterruptedException  ix  )   {
                        print ( "interrupted!" );
                     }   catch   (   Exception  x  )   {
                        print ( "threw an Exception!!!\n"   +  x );
                     }
                 }
             };

         Runnable  runB  =   new   Runnable ()   {
                 public   void  run ()   {
                    en . addItem ( "Hello!" );
                 }
             };

         try   {
             Thread  threadA1  =   new   Thread ( runA ,   "threadA1" );
            threadA1 . start ();

             Thread . sleep ( 500 );
    
             // start a *second* thread trying to remove
             Thread  threadA2  =   new   Thread ( runA ,   "threadA2" );
            threadA2 . start ();

             Thread . sleep ( 500 );
    
             Thread  threadB  =   new   Thread ( runB ,   "threadB" );
            threadB . start ();

             Thread . sleep ( 10000 );   // wait 10 seconds

            threadA1 . interrupt ();
            threadA2 . interrupt ();
         }   catch   (   InterruptedException  x  )   {
             // ignore
         }
     }
}

source/chapter08/EarlyNotifyFix.java

source/chapter08/EarlyNotifyFix.java

import  java . util . * ;

public   class   EarlyNotifyFix   extends   Object   {
     private   List  list ;

     public   EarlyNotifyFix ()   {
        list  =   Collections . synchronizedList ( new   LinkedList ());
     }

     public   String  removeItem ()   throws   InterruptedException   {
        print ( "in removeItem() - entering" );

         synchronized   (  list  )   {
             while   (  list . isEmpty ()   )   {
                print ( "in removeItem() - about to wait()" );
                list . wait ();
                print ( "in removeItem() - done with wait()" );
             }

             // extract the new first item
             String  item  =   ( String )  list . remove ( 0 );

            print ( "in removeItem() - leaving" );
             return  item ;
         }
     }

     public   void  addItem ( String  item )   {
        print ( "in addItem() - entering" );
         synchronized   (  list  )   {
             // There'll always be room to add to this List 
             // because it expands as needed. 
            list . add ( item );
            print ( "in addItem() - just added: '"   +  item  +   "'" );

             // After adding, notify any and all waiting 
             // threads that the list has changed.
            list . notifyAll ();
            print ( "in addItem() - just notified" );
         }
        print ( "in addItem() - leaving" );
     }

     private   static   void  print ( String  msg )   {
         String  name  =   Thread . currentThread (). getName ();
         System . out . println ( name  +   ": "   +  msg );
     }

     public   static   void  main ( String []  args )   {
         final   EarlyNotifyFix  enf  =   new   EarlyNotifyFix ();

         Runnable  runA  =   new   Runnable ()   {
                 public   void  run ()   {
                     try   {
                         String  item  =  enf . removeItem ();
                        print ( "in run() - returned: '"   +  
                                item  +   "'" );
                     }   catch   (   InterruptedException  ix  )   {
                        print ( "interrupted!" );
                     }   catch   (   Exception  x  )   {
                        print ( "threw an Exception!!!\n"   +  x );
                     }
                 }
             };

         Runnable  runB  =   new   Runnable ()   {
                 public   void  run ()   {
                    enf . addItem ( "Hello!" );
                 }
             };

         try   {
             Thread  threadA1  =   new   Thread ( runA ,   "threadA1" );
            threadA1 . start ();

             Thread . sleep ( 500 );
    
             // start a *second* thread trying to remove
             Thread  threadA2  =   new   Thread ( runA ,   "threadA2" );
            threadA2 . start ();

             Thread . sleep ( 500 );
    
             Thread  threadB  =   new   Thread ( runB ,   "threadB" );
            threadB . start ();

             Thread . sleep ( 10000 );   // wait 10 seconds

            threadA1 . interrupt ();
            threadA2 . interrupt ();
         }   catch   (   InterruptedException  x  )   {
             // ignore
         }
     }
}

source/chapter08/InheritableThreadID.java

source/chapter08/InheritableThreadID.java

public   class   InheritableThreadID   extends   Object   {
     public   static   final   int  UNIQUE   =   101 ;
     public   static   final   int  INHERIT  =   102 ;
     public   static   final   int  SUFFIX   =   103 ;

     private   ThreadLocal  threadLocal ;
     private   int  nextID ;

     public   InheritableThreadID ( int  type )   {
        nextID  =   201 ;

         switch   (  type  )   {
             case  UNIQUE :
                threadLocal  =   new   ThreadLocal ()   {
                         // override from ThreadLocal
                         protected   Object  initialValue ()   {
                            print ( "in initialValue()" );
                             return  getNewID ();
                         }
                     };
                 break ;

             case  INHERIT :
                threadLocal  =   new   InheritableThreadLocal ()   {
                         // override from ThreadLocal
                         protected   Object  initialValue ()   {
                            print ( "in initialValue()" );
                             return  getNewID ();
                         }
                     };
                 break ;

             case  SUFFIX :
                threadLocal  =   new   InheritableThreadLocal ()   {
                         // override from ThreadLocal
                         protected   Object  initialValue ()   {
                            print ( "in initialValue()" );
                             return  getNewID ();
                         }

                         // override from InheritableThreadLocal
                         protected   Object  childValue (
                                     Object  parentValue
                                 )   {

                            print ( "in childValue() - "   +
                                 "parentValue="   +  parentValue );

                             return  parentValue  +   "-CH" ;
                         }
                     };
                 break ;
             default :
                 break ;
         }
     }

     private   synchronized   String  getNewID ()   {
         String  id  =   "ID"   +  nextID ;
        nextID ++ ;
         return  id ;
     }

     public   String  getID ()   {
         return   ( String )  threadLocal . get ();
     }

     public   static   void  print ( String  msg )   {
         String  name  =   Thread . currentThread (). getName ();
         System . out . println ( name  +   ": "   +  msg );
     }

     public   static   Runnable  createTarget ( InheritableThreadID  id )   {
         final   InheritableThreadID  var  =  id ;

         Runnable  parentRun  =   new   Runnable ()   {
             public   void  run ()   {
                print ( "var.getID()="   +  var . getID ());
                print ( "var.getID()="   +  var . getID ());
                print ( "var.getID()="   +  var . getID ());

                 Runnable  childRun  =   new   Runnable ()   {
                         public   void  run ()   {
                            print ( "var.getID()="   +  var . getID ());
                            print ( "var.getID()="   +  var . getID ());
                            print ( "var.getID()="   +  var . getID ());
                         }
                     };

                 Thread  parentT  =   Thread . currentThread ();
                 String  parentName  =  parentT . getName ();
                print ( "creating a child thread of "   +
                    parentName );

                 Thread  childT  =   new   Thread ( childRun ,  
                        parentName  +   "-child" );
                childT . start ();
             }
         };

         return  parentRun ;
     }

     public   static   void  main ( String []  args )   {
         try   {
             System . out . println ( "======= ThreadLocal =======" );
             InheritableThreadID  varA  =  
                 new   InheritableThreadID ( UNIQUE );

             Runnable  targetA  =  createTarget ( varA );
             Thread  threadA  =   new   Thread ( targetA ,   "threadA" );
            threadA . start ();

             Thread . sleep ( 2500 );
             System . out . println ( "\n======= "   +
                 "InheritableThreadLocal =======" );

             InheritableThreadID  varB  =  
                 new   InheritableThreadID ( INHERIT );

             Runnable  targetB  =  createTarget ( varB );
             Thread  threadB  =   new   Thread ( targetB ,   "threadB" );
            threadB . start ();

             Thread . sleep ( 2500 );
             System . out . println ( "\n======= "   +
                 "InheritableThreadLocal - custom childValue()"   +
                 " =======" );

             InheritableThreadID  varC  =  
                 new   InheritableThreadID ( SUFFIX );

             Runnable  targetC  =  createTarget ( varC );
             Thread  threadC  =   new   Thread ( targetC ,   "threadC" );
            threadC . start ();
         }   catch   (   InterruptedException  x  )   {
             // ignore
         }

     }
}

source/chapter08/JoinDemo.java

source/chapter08/JoinDemo.java

public   class   JoinDemo   extends   Object   {
     public   static   Thread  launch ( String  name ,   long  napTime )   {
         final   long  sleepTime  =  napTime ;

         Runnable  r  =   new   Runnable ()   {
                 public   void  run ()   {
                     try   {
                        print ( "in run() - entering" );
                         Thread . sleep ( sleepTime );
                     }   catch   (   InterruptedException  x  )   {
                        print ( "interrupted!" );
                     }   finally   {
                        print ( "in run() - leaving" );
                     }
                 }
             };
    
         Thread  t  =   new   Thread ( r ,  name );
        t . start ();

         return  t ;
     }

     private   static   void  print ( String  msg )   {
         String  name  =   Thread . currentThread (). getName ();
         System . out . println ( name  +   ": "   +  msg );
     }

     public   static   void  main ( String []  args )   {
         Thread []  t  =   new   Thread [ 3 ];

        t [ 0 ]   =  launch ( "threadA" ,   2000 );
        t [ 1 ]   =  launch ( "threadB" ,   1000 );
        t [ 2 ]   =  launch ( "threadC" ,   3000 );

         for   (   int  i  =   0 ;  i  <  t . length ;  i ++   )   {
             try   {
                 String  idxStr  =   "t["   +  i  +   "]" ;
                 String  name  =   "["   +  t [ i ]. getName ()   +   "]" ;

                print ( idxStr  +   ".isAlive()="   +  
                        t [ i ]. isAlive ()   +   " "   +  name );
                print ( "about to do: "   +  idxStr  +  
                         ".join() "   +  name );

                 long  start  =   System . currentTimeMillis ();
                t [ i ]. join ();   // wait for the thread to die
                 long  stop  =   System . currentTimeMillis ();

                print ( idxStr  +   ".join() - took "   +  
                         (  stop  -  start  )   +   " ms "   +  name );
             }   catch   (   InterruptedException  x  )   {
                print ( "interrupted waiting on #"   +  i );
             }
         }
     }
}

source/chapter08/MissedNotify.java

source/chapter08/MissedNotify.java

public   class   MissedNotify   extends   Object   {
     private   Object  proceedLock ;

     public   MissedNotify ()   {
        print ( "in MissedNotify()" );
        proceedLock  =   new   Object ();
     }

     public   void  waitToProceed ()   throws   InterruptedException   {
        print ( "in waitToProceed() - entered" );

         synchronized   (  proceedLock  )   {
            print ( "in waitToProceed() - about to wait()" );
            proceedLock . wait ();
            print ( "in waitToProceed() - back from wait()" );
         }

        print ( "in waitToProceed() - leaving" );
     }

     public   void  proceed ()   {
        print ( "in proceed() - entered" );

         synchronized   (  proceedLock  )   {
            print ( "in proceed() - about to notifyAll()" );
            proceedLock . notifyAll ();
            print ( "in proceed() - back from notifyAll()" );
         }

        print ( "in proceed() - leaving" );
     }

     private   static   void  print ( String  msg )   {
         String  name  =   Thread . currentThread (). getName ();
         System . out . println ( name  +   ": "   +  msg );
     }

     public   static   void  main ( String []  args )   {
         final   MissedNotify  mn  =   new   MissedNotify ();

         Runnable  runA  =   new   Runnable ()   {
                 public   void  run ()   {
                     try   {
                         Thread . sleep ( 1000 );
                        mn . waitToProceed ();
                     }   catch   (   InterruptedException  x  )   {
                        x . printStackTrace ();
                     }
                 }
             };

         Thread  threadA  =   new   Thread ( runA ,   "threadA" );
        threadA . start ();

         Runnable  runB  =   new   Runnable ()   {
                 public   void  run ()   {
                     try   {
                         Thread . sleep ( 500 );
                        mn . proceed ();
                     }   catch   (   InterruptedException  x  )   {
                        x . printStackTrace ();
                     }
                 }
             };

         Thread  threadB  =   new   Thread ( runB ,   "threadB" );
        threadB . start ();

         try   {  
             Thread . sleep ( 10000 );
         }   catch   (   InterruptedException  x  )   {
         }

        print ( "about to invoke interrupt() on threadA" );
        threadA . interrupt ();
     }
}

source/chapter08/MissedNotifyFix.java

source/chapter08/MissedNotifyFix.java

public   class   MissedNotifyFix   extends   Object   {
     private   Object  proceedLock ;
     private   boolean  okToProceed ;

     public   MissedNotifyFix ()   {
        print ( "in MissedNotify()" );
        proceedLock  =   new   Object ();
        okToProceed  =   false ;
     }

     public   void  waitToProceed ()   throws   InterruptedException   {
        print ( "in waitToProceed() - entered" );

         synchronized   (  proceedLock  )   {
            print ( "in waitToProceed() - entered sync block" );

             while   (  okToProceed  ==   false   )   {
                print ( "in waitToProceed() - about to wait()" );
                proceedLock . wait ();
                print ( "in waitToProceed() - back from wait()" );
             }

            print ( "in waitToProceed() - leaving sync block" );
         }

        print ( "in waitToProceed() - leaving" );
     }

     public   void  proceed ()   {
        print ( "in proceed() - entered" );

         synchronized   (  proceedLock  )   {
            print ( "in proceed() - entered sync block" );

            okToProceed  =   true ;
            print ( "in proceed() - changed okToProceed to true" );
            proceedLock . notifyAll ();
            print ( "in proceed() - just did notifyAll()" );

            print ( "in proceed() - leaving sync block" );
         }

        print ( "in proceed() - leaving" );
     }

     private   static   void  print ( String  msg )   {
         String  name  =   Thread . currentThread (). getName ();
         System . out . println ( name  +   ": "   +  msg );
     }

     public   static   void  main ( String []  args )   {
         final   MissedNotifyFix  mnf  =   new   MissedNotifyFix ();

         Runnable  runA  =   new   Runnable ()   {
                 public   void  run ()   {
                     try   {
                         Thread . sleep ( 1000 );
                        mnf . waitToProceed ();
                     }   catch   (   InterruptedException  x  )   {
                        x . printStackTrace ();
                     }
                 }
             };

         Thread  threadA  =   new   Thread ( runA ,   "threadA" );
        threadA . start ();

         Runnable  runB  =   new   Runnable ()   {
                 public   void  run ()   {
                     try   {
                         Thread . sleep ( 500 );
                        mnf . proceed ();
                     }   catch   (   InterruptedException  x  )   {
                        x . printStackTrace ();
                     }
                 }
             };

         Thread  threadB  =   new   Thread ( runB ,   "threadB" );
        threadB . start ();

         try   {  
             Thread . sleep ( 10000 );
         }   catch   (   InterruptedException  x  )   {
         }

        print ( "about to invoke interrupt() on threadA" );
        threadA . interrupt ();
     }
}

source/chapter08/PipedBytes.java

source/chapter08/PipedBytes.java

import  java . io . * ;

public   class   PipedBytes   extends   Object   {
     public   static   void  writeStuff ( OutputStream  rawOut )   {
         try   {
             DataOutputStream  out  =   new   DataOutputStream (
                     new   BufferedOutputStream ( rawOut ));
    
             int []  data  =   {   82 ,   105 ,   99 ,   104 ,   97 ,   114 ,   100 ,   32 ,  
                            72 ,   121 ,   100 ,   101   };

             for   (   int  i  =   0 ;  i  <  data . length ;  i ++   )   {
                out . writeInt ( data [ i ]);
             }

            out . flush ();
            out . close ();
         }   catch   (   IOException  x  )   {
            x . printStackTrace ();
         }
     }

     public   static   void  readStuff ( InputStream  rawIn )   {
         try   {
             DataInputStream  in  =   new   DataInputStream (
                     new   BufferedInputStream ( rawIn ));

             boolean  eof  =   false ;
             while   (   ! eof  )   {
                 try   {
                     int  i  =  in . readInt ();
                     System . out . println ( "just read: "   +  i );
                 }   catch   (   EOFException  eofx  )   {
                    eof  =   true ;
                 }
             }

             System . out . println ( "Read all data from the pipe" );
         }   catch   (   IOException  x  )   {
            x . printStackTrace ();
         }
     }

     public   static   void  main ( String []  args )   {
         try   {
             final   PipedOutputStream  out  =  
                     new   PipedOutputStream ();

             final   PipedInputStream  in  =  
                     new   PipedInputStream ( out );

             Runnable  runA  =   new   Runnable ()   {
                     public   void  run ()   {
                        writeStuff ( out );
                     }
                 };

             Thread  threadA  =   new   Thread ( runA ,   "threadA" );
            threadA . start ();
    
             Runnable  runB  =   new   Runnable ()   {
                     public   void  run ()   {
                        readStuff ( in );
                     }
                 };
    
             Thread  threadB  =   new   Thread ( runB ,   "threadB" );
            threadB . start ();
         }   catch   (   IOException  x  )   {
            x . printStackTrace ();
         }
     }
}

source/chapter08/PipedCharacters.java

source/chapter08/PipedCharacters.java

import  java . io . * ;

public   class   PipedCharacters   extends   Object   {
     public   static   void  writeStuff ( Writer  rawOut )   {
         try   {
             BufferedWriter  out  =   new   BufferedWriter ( rawOut );
    
             String [][]  line  =   {
                     {   "Java" ,   "has" ,   "nice" ,   "features."   },
                     {   "Pipes" ,   "are" ,   "interesting."   },
                     {   "Threads" ,   "are" ,   "fun" ,   "in" ,   "Java."   },
                     {   "Don't" ,   "you" ,   "think" ,   "so?"   }
                 };

             for   (   int  i  =   0 ;  i  <  line . length ;  i ++   )   {
                 String []  word  =  line [ i ];

                 for   (   int  j  =   0 ;  j  <  word . length ;  j ++   )   {
                     if   (  j  >   0   )   {
                         // put a space between words
                        out . write ( " " );
                     }  

                    out . write ( word [ j ]);
                 }

                 // mark the end of a line
                out . newLine ();
             }

            out . flush ();
            out . close ();
         }   catch   (   IOException  x  )   {
            x . printStackTrace ();
         }
     }

     public   static   void  readStuff ( Reader  rawIn )   {
         try   {
             BufferedReader  in  =   new   BufferedReader ( rawIn );

             String  line ;
             while   (   (  line  =  in . readLine ()   )   !=   null   )   {
                 System . out . println ( "read line: "   +  line );
             }

             System . out . println ( "Read all data from the pipe" );
         }   catch   (   IOException  x  )   {
            x . printStackTrace ();
         }
     }

     public   static   void  main ( String []  args )   {
         try   {
             final   PipedWriter  out  =   new   PipedWriter ();

             final   PipedReader  in  =   new   PipedReader ( out );

             Runnable  runA  =   new   Runnable ()   {
                     public   void  run ()   {
                        writeStuff ( out );
                     }
                 };

             Thread  threadA  =   new   Thread ( runA ,   "threadA" );
            threadA . start ();
    
             Runnable  runB  =   new   Runnable ()   {
                     public   void  run ()   {
                        readStuff ( in );
                     }
                 };
    
             Thread  threadB  =   new   Thread ( runB ,   "threadB" );
            threadB . start ();
         }   catch   (   IOException  x  )   {
            x . printStackTrace ();
         }
     }
}

source/chapter08/ThreadID.java

source/chapter08/ThreadID.java

public   class   ThreadID   extends   ThreadLocal   {
     private   int  nextID ;

     public   ThreadID ()   {
        nextID  =   10001 ;
     }

     private   synchronized   Integer  getNewID ()   {
         Integer  id  =   new   Integer ( nextID );
        nextID ++ ;
         return  id ;
     }

     // override ThreadLocal's version
     protected   Object  initialValue ()   {
        print ( "in initialValue()" );
         return  getNewID ();
     }

     public   int  getThreadID ()   {
         // Call get() in ThreadLocal to get the calling
         // thread's unique ID.
         Integer  id  =   ( Integer )  get ();  
         return  id . intValue ();
     }

     private   static   void  print ( String  msg )   {
         String  name  =   Thread . currentThread (). getName ();
         System . out . println ( name  +   ": "   +  msg );
     }
}

source/chapter08/ThreadIDMain.java

source/chapter08/ThreadIDMain.java

public   class   ThreadIDMain   extends   Object   implements   Runnable   {
     private   ThreadID  var ;

     public   ThreadIDMain ( ThreadID  var )   {
         this . var  =  var ;
     }

     public   void  run ()   {
         try   {  
            print ( "var.getThreadID()="   +  var . getThreadID ());
             Thread . sleep ( 2000 );  
            print ( "var.getThreadID()="   +  var . getThreadID ());
         }   catch   (   InterruptedException  x  )   {
             // ignore
         }
     }

     private   static   void  print ( String  msg )   {
         String  name  =   Thread . currentThread (). getName ();
         System . out . println ( name  +   ": "   +  msg );
     }

     public   static   void  main ( String []  args )   {
         ThreadID  tid  =   new   ThreadID ();
         ThreadIDMain  shared  =   new   ThreadIDMain ( tid );

         try   {
             Thread  threadA  =   new   Thread ( shared ,   "threadA" );
            threadA . start ();

             Thread . sleep ( 500 );

             Thread  threadB  =   new   Thread ( shared ,   "threadB" );
            threadB . start ();

             Thread . sleep ( 500 );

             Thread  threadC  =   new   Thread ( shared ,   "threadC" );
            threadC . start ();
         }   catch   (   InterruptedException  x  )   {
             // ignore
         }
     }
}

source/chapter09/BalanceLookup.java

source/chapter09/BalanceLookup.java

import  java . awt . * ;
import  java . awt . event . * ;
import  javax . swing . * ;

public   class   BalanceLookup   extends   JPanel   {
     private   JTextField  acctTF ;
     private   JTextField  pinTF ;
     private   JButton  searchB ;
     private   JButton  cancelB ;
     private   JLabel  balanceL ;

     private   volatile   Thread  lookupThread ;

     public   BalanceLookup ()   {
        buildGUI ();
        hookupEvents ();
     }

     private   void  buildGUI ()   {
         JLabel  acctL  =   new   JLabel ( "Account Number:" );
         JLabel  pinL  =   new   JLabel ( "PIN:" );
        acctTF  =   new   JTextField ( 12 );
        pinTF  =   new   JTextField ( 4 );

         JPanel  dataEntryP  =   new   JPanel ();
        dataEntryP . setLayout ( new   FlowLayout ( FlowLayout . CENTER ));
        dataEntryP . add ( acctL );
        dataEntryP . add ( acctTF );
        dataEntryP . add ( pinL );
        dataEntryP . add ( pinTF );

        searchB  =   new   JButton ( "Search" );
        cancelB  =   new   JButton ( "Cancel Search" );
        cancelB . setEnabled ( false );

         JPanel  innerButtonP  =   new   JPanel ();
        innerButtonP . setLayout ( new   GridLayout ( 1 ,   - 1 ,   5 ,   5 ));
        innerButtonP . add ( searchB );
        innerButtonP . add ( cancelB );

         JPanel  buttonP  =   new   JPanel ();
        buttonP . setLayout ( new   FlowLayout ( FlowLayout . CENTER ));
        buttonP . add ( innerButtonP );

         JLabel  balancePrefixL  =   new   JLabel ( "Account Balance:" );
        balanceL  =   new   JLabel ( "BALANCE UNKNOWN" );

         JPanel  balanceP  =   new   JPanel ();
        balanceP . setLayout ( new   FlowLayout ( FlowLayout . CENTER ));
        balanceP . add ( balancePrefixL );
        balanceP . add ( balanceL );

         JPanel  northP  =   new   JPanel ();
        northP . setLayout ( new   GridLayout ( - 1 ,   1 ,   5 ,   5 ));
        northP . add ( dataEntryP );
        northP . add ( buttonP );
        northP . add ( balanceP );

        setLayout ( new   BorderLayout ());
        add ( northP ,   BorderLayout . NORTH );
     }

     private   void  hookupEvents ()   {
        searchB . addActionListener ( new   ActionListener ()   {
                 public   void  actionPerformed ( ActionEvent  e )   {
                    search ();
                 }
             });

        cancelB . addActionListener ( new   ActionListener ()   {
                 public   void  actionPerformed ( ActionEvent  e )   {
                    cancelSearch ();
                 }
             });
     }

     private   void  search ()   {
         // better be called by event thread!
        ensureEventThread ();

        searchB . setEnabled ( false );
        cancelB . setEnabled ( true );
        balanceL . setText ( "SEARCHING ..." );

         // get a snapshot of this info in case it changes
         String  acct  =  acctTF . getText ();
         String  pin  =  pinTF . getText ();

        lookupAsync ( acct ,  pin );
     }

     private   void  lookupAsync ( String  acct ,   String  pin )   {
         // Called by event thread, but can be safely 
         // called by any thread.
         final   String  acctNum  =  acct ;
         final   String  pinNum  =  pin ;

         Runnable  lookupRun  =   new   Runnable ()   {
                 public   void  run ()   {
                     String  bal  =  lookupBalance ( acctNum ,  pinNum );
                    setBalanceSafely ( bal );
                 }
             };
        
        lookupThread  =   new   Thread ( lookupRun ,   "lookupThread" );
        lookupThread . start ();
     }
    
     private   String  lookupBalance ( String  acct ,   String  pin )   {
         // Called by lookupThread, but can be safely 
         // called by any thread.
         try   {
             // Simulate a lengthy search that takes 5 seconds
             // to communicate over the network.
             Thread . sleep ( 5000 );

             // result "retrieved", return it
             return   "1,234.56" ;
         }   catch   (   InterruptedException  x  )   {
             return   "SEARCH CANCELLED" ;
         }
     }

     private   void  setBalanceSafely ( String  newBal )   {
         // Called by lookupThread, but can be safely 
         // called by any thread.
         final   String  newBalance  =  newBal ;

         Runnable  r  =   new   Runnable ()   {
                 public   void  run ()   {
                     try   {
                        setBalance ( newBalance );
                     }   catch   (   Exception  x  )   {
                        x . printStackTrace ();
                     }
                 }
             };
        
         SwingUtilities . invokeLater ( r );
     }

     private   void  setBalance ( String  newBalance )   {
         // better be called by event thread!
        ensureEventThread ();

        balanceL . setText ( newBalance );
        cancelB . setEnabled ( false );
        searchB . setEnabled ( true );
     }

     private   void  cancelSearch ()   {
         // better be called by event thread!
        ensureEventThread ();

        cancelB . setEnabled ( false );   // prevent additional requests

         if   (  lookupThread  !=   null   )   {
            lookupThread . interrupt ();
         }
     }

     private   void  ensureEventThread ()   {
         // throws an exception if not invoked by the 
         // event thread.
         if   (   SwingUtilities . isEventDispatchThread ()   )   {
             return ;
         }

         throw   new   RuntimeException ( "only the event "   +
             "thread should invoke this method" );
     }

     public   static   void  main ( String []  args )   {
         BalanceLookup  bl  =   new   BalanceLookup ();

         JFrame  f  =   new   JFrame ( "Balance Lookup" );
        f . addWindowListener ( new   WindowAdapter ()   {
                 public   void  windowClosing ( WindowEvent  e )   {
                     System . exit ( 0 );
                 }
             });

        f . setContentPane ( bl );
        f . setSize ( 400 ,   150 );
        f . setVisible ( true );
     }
}

source/chapter09/BalanceLookupCantCancel.java

source/chapter09/BalanceLookupCantCancel.java

import  java . awt . * ;
import  java . awt . event . * ;
import  javax . swing . * ;

public   class   BalanceLookupCantCancel   extends   JPanel   {
     private   JTextField  acctTF ;
     private   JTextField  pinTF ;
     private   JButton  searchB ;
     private   JButton  cancelB ;
     private   JLabel  balanceL ;

     public   BalanceLookupCantCancel ()   {
        buildGUI ();
        hookupEvents ();
     }

     private   void  buildGUI ()   {
         JLabel  acctL  =   new   JLabel ( "Account Number:" );
         JLabel  pinL  =   new   JLabel ( "PIN:" );
        acctTF  =   new   JTextField ( 12 );
        pinTF  =   new   JTextField ( 4 );

         JPanel  dataEntryP  =   new   JPanel ();
        dataEntryP . setLayout ( new   FlowLayout ( FlowLayout . CENTER ));
        dataEntryP . add ( acctL );
        dataEntryP . add ( acctTF );
        dataEntryP . add ( pinL );
        dataEntryP . add ( pinTF );

        searchB  =   new   JButton ( "Search" );
        cancelB  =   new   JButton ( "Cancel Search" );
        cancelB . setEnabled ( false );

         JPanel  innerButtonP  =   new   JPanel ();
        innerButtonP . setLayout ( new   GridLayout ( 1 ,   - 1 ,   5 ,   5 ));
        innerButtonP . add ( searchB );
        innerButtonP . add ( cancelB );

         JPanel  buttonP  =   new   JPanel ();
        buttonP . setLayout ( new   FlowLayout ( FlowLayout . CENTER ));
        buttonP . add ( innerButtonP );

         JLabel  balancePrefixL  =   new   JLabel ( "Account Balance:" );
        balanceL  =   new   JLabel ( "BALANCE UNKNOWN" );

         JPanel  balanceP  =   new   JPanel ();
        balanceP . setLayout ( new   FlowLayout ( FlowLayout . CENTER ));
        balanceP . add ( balancePrefixL );
        balanceP . add ( balanceL );

         JPanel  northP  =   new   JPanel ();
        northP . setLayout ( new   GridLayout ( - 1 ,   1 ,   5 ,   5 ));
        northP . add ( dataEntryP );
        northP . add ( buttonP );
        northP . add ( balanceP );

        setLayout ( new   BorderLayout ());
        add ( northP ,   BorderLayout . NORTH );
     }

     private   void  hookupEvents ()   {
        searchB . addActionListener ( new   ActionListener ()   {
                 public   void  actionPerformed ( ActionEvent  e )   {
                    search ();
                 }
             });

        cancelB . addActionListener ( new   ActionListener ()   {
                 public   void  actionPerformed ( ActionEvent  e )   {
                    cancelSearch ();
                 }
             });
     }

     private   void  search ()   {
         // better be called by event thread!
        searchB . setEnabled ( false );
        cancelB . setEnabled ( true );
        balanceL . setText ( "SEARCHING ..." );

         // get a snapshot of this info in case it changes
         String  acct  =  acctTF . getText ();
         String  pin  =  pinTF . getText ();

         String  bal  =  lookupBalance ( acct ,  pin );
        setBalance ( bal );
     }

     private   String  lookupBalance ( String  acct ,   String  pin )   {
         try   {
             // Simulate a lengthy search that takes 5 seconds
             // to communicate over the network.
             Thread . sleep ( 5000 );

             // result "retrieved", return it
             return   "1,234.56" ;
         }   catch   (   InterruptedException  x  )   {
             return   "SEARCH CANCELLED" ;
         }
     }

     private   void  setBalance ( String  newBalance )   {
         // better be called by event thread!
        balanceL . setText ( newBalance );
        cancelB . setEnabled ( false );
        searchB . setEnabled ( true );
     }

     private   void  cancelSearch ()   {
         System . out . println ( "in cancelSearch()" );
         // Here's where the code to cancel would go if this
         // could ever be called!
     }

     public   static   void  main ( String []  args )   {
         BalanceLookupCantCancel  bl  =  
                 new   BalanceLookupCantCancel ();

         JFrame  f  =   new   JFrame ( "Balance Lookup - Can't Cancel" );
        f . addWindowListener ( new   WindowAdapter ()   {
                 public   void  windowClosing ( WindowEvent  e )   {
                     System . exit ( 0 );
                 }
             });

        f . setContentPane ( bl );
        f . setSize ( 400 ,   150 );
        f . setVisible ( true );
     }
}

source/chapter09/CompMover.java

source/chapter09/CompMover.java

import  java . awt . * ;
import  javax . swing . * ;

public   class   CompMover   extends   Object   {
     private   Component  comp ;
     private   int  initX ;
     private   int  initY ;
     private   int  offsetX ;
     private   int  offsetY ;
     private   boolean  firstTime ;
     private   Runnable  updatePositionRun ;

     private   Thread  internalThread ;
     private   volatile   boolean  noStopRequested ;

     public   CompMover ( Component  comp ,  
                 int  initX ,   int  initY ,
                 int  offsetX ,   int  offsetY
             )   {

         this . comp  =  comp ;
         this . initX  =  initX ;
         this . initY  =  initY ;
         this . offsetX  =  offsetX ;
         this . offsetY  =  offsetY ;

        firstTime  =   true ;

        updatePositionRun  =   new   Runnable ()   {
                 public   void  run ()   {
                    updatePosition ();
                 }
             };

        noStopRequested  =   true ;
         Runnable  r  =   new   Runnable ()   {
                 public   void  run ()   {
                     try   {
                        runWork ();
                     }   catch   (   Exception  x  )   {
                         // in case ANY exception slips through
                        x . printStackTrace ();  
                     }
                 }
             };

        internalThread  =   new   Thread ( r );
        internalThread . start ();
     }

     private   void  runWork ()   {
         while   (  noStopRequested  )   {
             try   {
                 Thread . sleep ( 200 );
                 SwingUtilities . invokeAndWait ( updatePositionRun );
             }   catch   (   InterruptedException  ix  )   {
                 // ignore
             }   catch   (   Exception  x  )   {
                x . printStackTrace ();
             }
         }
     }

     public   void  stopRequest ()   {
        noStopRequested  =   false ;
        internalThread . interrupt ();
     }

     public   boolean  isAlive ()   {
         return  internalThread . isAlive ();
     }

     private   void  updatePosition ()   {
         // should only be called by the *event* thread

         if   (   ! comp . isVisible ()   )   {
             return ;
         }

         Component  parent  =  comp . getParent ();
         if   (  parent  ==   null   )   {
             return ;
         }

         Dimension  parentSize  =  parent . getSize ();
         if   (   (  parentSize  ==   null   )   &&
              (  parentSize . width  <   1   )   &&  
              (  parentSize . height  <   1   )  
            )   {

             return ;
         }

         int  newX  =   0 ;
         int  newY  =   0 ;

         if   (  firstTime  )   {
            firstTime  =   false ;
            newX  =  initX ;
            newY  =  initY ;
         }   else   {
             Point  loc  =  comp . getLocation ();
            newX  =  loc . +  offsetX ;
            newY  =  loc . +  offsetY ;
         }

        newX  =  newX  %  parentSize . width ;
        newY  =  newY  %  parentSize . height ;

         if   (  newX  <   0   )   {
             // wrap around other side
            newX  +=  parentSize . width ;
         }

         if   (  newY  <   0   )   {
             // wrap around other side
            newY  +=  parentSize . height ;
         }

        comp . setLocation ( newX ,  newY );
        parent . repaint ();
     }

     public   static   void  main ( String []  args )   {
         Component []  comp  =   new   Component [ 6 ];

        comp [ 0 ]   =   new   ScrollText ( "Scrolling Text" );
        comp [ 1 ]   =   new   ScrollText ( "Java Threads" );
        comp [ 2 ]   =   new   SlideShow ();
        comp [ 3 ]   =   new   SlideShow ();
        comp [ 4 ]   =   new   DigitalTimer ();
        comp [ 5 ]   =   new   DigitalTimer ();

         JPanel  p  =   new   JPanel ();
        p . setLayout ( null );   // no layout manager

         for   (   int  i  =   0 ;  i  <  comp . length ;  i ++   )   {
            p . add ( comp [ i ]);

             int  x  =   ( int )   (   300   *   Math . random ()   );
             int  y  =   ( int )   (   200   *   Math . random ()   );
             int  xOff  =   2   -   ( int )   (   5   *   Math . random ()   );
             int  yOff  =   2   -   ( int )   (   5   *   Math . random ()   );

             new   CompMover ( comp [ i ],  x ,  y ,  xOff ,  yOff );
         }

         JFrame  f  =   new   JFrame ( "CompMover Demo" );
        f . setContentPane ( p );
        f . setSize ( 400 ,   300 );
        f . setVisible ( true );
     }
}

source/chapter09/DigitalTimer.java

source/chapter09/DigitalTimer.java

import  java . awt . * ;
import  java . text . * ;
import  java . lang . reflect . * ;
import  javax . swing . * ;

public   class   DigitalTimer   extends   JLabel   {
     private   volatile   String  timeText ;

     private   Thread  internalThread ;
     private   volatile   boolean  noStopRequested ;

     public   DigitalTimer ()   {
        setBorder ( BorderFactory . createLineBorder ( Color . black ));
        setHorizontalAlignment ( SwingConstants . RIGHT );
        setFont ( new   Font ( "SansSerif" ,   Font . BOLD ,   16 ));
        setText ( "00000.0" );   // use to size component
        setMinimumSize ( getPreferredSize ());
        setPreferredSize ( getPreferredSize ());
        setSize ( getPreferredSize ());

        timeText  =   "0.0" ;
        setText ( timeText );

        noStopRequested  =   true ;
         Runnable  r  =   new   Runnable ()   {
                 public   void  run ()   {
                     try   {
                        runWork ();
                     }   catch   (   Exception  x  )   {
                        x . printStackTrace ();  
                     }
                 }
             };

        internalThread  =   new   Thread ( r ,   "DigitalTimer" );
        internalThread . start ();
     }

     private   void  runWork ()   {
         long  startTime  =   System . currentTimeMillis ();
         int  tenths  =   0 ;
         long  normalSleepTime  =   100 ;
         long  nextSleepTime  =   100 ;
         DecimalFormat  fmt  =   new   DecimalFormat ( "0.0" );

         Runnable  updateText  =   new   Runnable ()   {
                 public   void  run ()   {
                    setText ( timeText );
                 }
             };

         while   (  noStopRequested  )   {
             try   {
                 Thread . sleep ( nextSleepTime );

                tenths ++ ;
                 long  currTime  =   System . currentTimeMillis ();
                 long  elapsedTime  =  currTime  -  startTime ;

                nextSleepTime  =  normalSleepTime  +  
                     (   (  tenths  *   100   )   -  elapsedTime  );

                 if   (  nextSleepTime  <   0   )   {
                    nextSleepTime  =   0 ;
                 }

                timeText  =  fmt . format ( elapsedTime  /   1000.0 );
                 SwingUtilities . invokeAndWait ( updateText );
             }   catch   (   InterruptedException  ix  )   {
                 // stop running
                 return ;
             }   catch   (   InvocationTargetException  x  )   {
                 // If an exception was thrown inside the
                 // run() method of the updateText Runnable.
                x . printStackTrace ();
             }
         }
     }

     public   void  stopRequest ()   {
        noStopRequested  =   false ;
        internalThread . interrupt ();
     }

     public   boolean  isAlive ()   {
         return  internalThread . isAlive ();
     }

     public   static   void  main ( String []  args )   {
         DigitalTimer  dt  =   new   DigitalTimer ();

         JPanel  p  =   new   JPanel ( new   FlowLayout ());
        p . add ( dt );

         JFrame  f  =   new   JFrame ( "DigitalTimer Demo" );
        f . setContentPane ( p );
        f . setSize ( 250 ,   100 );
        f . setVisible ( true );
     }
}

source/chapter09/InvokeAndWaitDemo.java

source/chapter09/InvokeAndWaitDemo.java

import  java . awt . * ;
import  java . awt . event . * ;
import  java . lang . reflect . * ;
import  javax . swing . * ;

public   class   InvokeAndWaitDemo   extends   Object   {
     private   static   void  print ( String  msg )   {
         String  name  =   Thread . currentThread (). getName ();
         System . out . println ( name  +   ": "   +  msg );
     }

     public   static   void  main ( String []  args )   {
         final   JLabel  label  =   new   JLabel ( "--------" );

         JPanel  panel  =   new   JPanel ( new   FlowLayout ());
        panel . add ( label );

         JFrame  f  =   new   JFrame ( "InvokeAndWaitDemo" );
        f . setContentPane ( panel );
        f . setSize ( 300 ,   100 );
        f . setVisible ( true );

         try   {
            print ( "sleeping for 3 seconds" );
             Thread . sleep ( 3000 );

            print ( "creating code block for event thread" );
             Runnable  setTextRun  =   new   Runnable ()   {
                     public   void  run ()   {
                        print ( "about to do setText()" );
                        label . setText ( "New text!" );
                     }
                 };
            
            print ( "about to invokeAndWait()" );
             SwingUtilities . invokeAndWait ( setTextRun );
            print ( "back from invokeAndWait()" );
         }   catch   (   InterruptedException  ix  )   {
            print ( "interrupted while waiting on invokeAndWait()" );
         }   catch   (   InvocationTargetException  x  )   {
            print ( "exception thrown from run()" );
         }
     }
}

source/chapter09/InvokeLaterDemo.java

source/chapter09/InvokeLaterDemo.java

import  java . awt . * ;
import  java . awt . event . * ;
import  javax . swing . * ;

public   class   InvokeLaterDemo   extends   Object   {
     private   static   void  print ( String  msg )   {
         String  name  =   Thread . currentThread (). getName ();
         System . out . println ( name  +   ": "   +  msg );
     }

     public   static   void  main ( String []  args )   {
         final   JLabel  label  =   new   JLabel ( "--------" );

         JPanel  panel  =   new   JPanel ( new   FlowLayout ());
        panel . add ( label );

         JFrame  f  =   new   JFrame ( "InvokeLaterDemo" );
        f . setContentPane ( panel );
        f . setSize ( 300 ,   100 );
        f . setVisible ( true );

         try   {
            print ( "sleeping for 3 seconds" );
             Thread . sleep ( 3000 );
         }   catch   (   InterruptedException  ix  )   {
            print ( "interrupted while sleeping" );
         }

        print ( "creating code block for event thread" );
         Runnable  setTextRun  =   new   Runnable ()   {
                 public   void  run ()   {
                     try   {
                         Thread . sleep ( 100 );   // for emphasis
                        print ( "about to do setText()" );
                        label . setText ( "New text!" );
                     }   catch   (   Exception  x  )   {
                        x . printStackTrace ();
                     }
                 }
             };
            
        print ( "about to invokeLater()" );
         SwingUtilities . invokeLater ( setTextRun );
        print ( "back from invokeLater()" );
     }
}

source/chapter09/ScrollText.java

source/chapter09/ScrollText.java

import  java . awt . * ;
import  java . awt . image . * ;
import  java . awt . font . * ;
import  java . awt . geom . * ;
import  javax . swing . * ;

public   class   ScrollText   extends   JComponent   {
     private   BufferedImage  image ;
     private   Dimension  imageSize ;
     private   volatile   int  currOffset ;

     private   Thread  internalThread ;
     private   volatile   boolean  noStopRequested ;

     public   ScrollText ( String  text )   {
        currOffset  =   0 ;
        buildImage ( text );

        setMinimumSize ( imageSize );
        setPreferredSize ( imageSize );
        setMaximumSize ( imageSize );
        setSize ( imageSize );

        noStopRequested  =   true ;
         Runnable  r  =   new   Runnable ()   {
                 public   void  run ()   {
                     try   {
                        runWork ();
                     }   catch   (   Exception  x  )   {
                        x . printStackTrace ();  
                     }
                 }
             };

        internalThread  =   new   Thread ( r ,   "ScrollText" );
        internalThread . start ();
     }

     private   void  buildImage ( String  text )   {
         // Request that the drawing be done with anti-aliasing
         // turned on and the quality high.
         RenderingHints  renderHints  =   new   RenderingHints (
             RenderingHints . KEY_ANTIALIASING ,
             RenderingHints . VALUE_ANTIALIAS_ON );

        renderHints . put (
             RenderingHints . KEY_RENDERING ,
             RenderingHints . VALUE_RENDER_QUALITY );

         // Create a scratch image for use in determining
         // the text dimensions.
         BufferedImage  scratchImage  =   new   BufferedImage (
                 1 ,   1 ,   BufferedImage . TYPE_INT_RGB );

         Graphics2D  scratchG2  =  scratchImage . createGraphics ();
        scratchG2 . setRenderingHints ( renderHints );

         Font  font  =  
             new   Font ( "Serif" ,   Font . BOLD  |   Font . ITALIC ,   24 );

         FontRenderContext  frc  =  scratchG2 . getFontRenderContext ();
         TextLayout  tl  =   new   TextLayout ( text ,  font ,  frc );
         Rectangle2D  textBounds  =  tl . getBounds ();
         int  textWidth  =   ( int )   Math . ceil ( textBounds . getWidth ());
         int  textHeight  =   ( int )   Math . ceil ( textBounds . getHeight ());

         int  horizontalPad  =   10 ;
         int  verticalPad  =   6 ;

        imageSize  =   new   Dimension (
                textWidth  +  horizontalPad ,
                textHeight  +  verticalPad
             );

         // Create the properly-sized image
        image  =   new   BufferedImage (
                imageSize . width ,
                imageSize . height ,
                 BufferedImage . TYPE_INT_RGB );

         Graphics2D  g2  =  image . createGraphics ();
        g2 . setRenderingHints ( renderHints );

         int  baselineOffset  =  
             (  verticalPad  /   2   )   -   (   ( int )  textBounds . getY ());

        g2 . setColor ( Color . white );
        g2 . fillRect ( 0 ,   0 ,  imageSize . width ,  imageSize . height );

        g2 . setColor ( Color . blue );
        tl . draw ( g2 ,   0 ,  baselineOffset );

         // Free-up resources right away, but keep "image" for
         // animation.
        scratchG2 . dispose ();
        scratchImage . flush ();
        g2 . dispose ();
     }

     public   void  paint ( Graphics  g )   {
         // Make sure to clip the edges, regardless of curr size
        g . setClip ( 0 ,   0 ,  imageSize . width ,  imageSize . height );

         int  localOffset  =  currOffset ;   // in case it changes
        g . drawImage ( image ,   - localOffset ,   0 ,   this );
        g . drawImage (
            image ,  imageSize . width  -  localOffset ,   0 ,   this );

         // draw outline
        g . setColor ( Color . black );
        g . drawRect (
             0 ,   0 ,  imageSize . width  -   1 ,  imageSize . height  -   1 );
     }

     private   void  runWork ()   {
         while   (  noStopRequested  )   {
             try   {
                 Thread . sleep ( 100 );    // 10 frames per second
                
                 // adjust the scroll position
                currOffset  =  
                     (  currOffset  +   1   )   %  imageSize . width ;

                 // signal the event thread to call paint()
                repaint ();
             }   catch   (   InterruptedException  x  )   {
                 Thread . currentThread (). interrupt ();  
             }
         }
     }

     public   void  stopRequest ()   {
        noStopRequested  =   false ;
        internalThread . interrupt ();
     }

     public   boolean  isAlive ()   {
         return  internalThread . isAlive ();
     }

     public   static   void  main ( String []  args )   {
         ScrollText  st  =  
             new   ScrollText ( "Java can do animation!" );

         JPanel  p  =   new   JPanel ( new   FlowLayout ());
        p . add ( st );

         JFrame  f  =   new   JFrame ( "ScrollText Demo" );
        f . setContentPane ( p );
        f . setSize ( 400 ,   100 );
        f . setVisible ( true );
     }
}

source/chapter09/SimpleEvent.java

source/chapter09/SimpleEvent.java

import  java . awt . * ;
import  java . awt . event . * ;
import  javax . swing . * ;

public   class   SimpleEvent   extends   Object   {
     private   static   void  print ( String  msg )   {
         String  name  =   Thread . currentThread (). getName ();
         System . out . println ( name  +   ": "   +  msg );
     }

     public   static   void  main ( String []  args )   {
         final   JLabel  label  =   new   JLabel ( "--------" );
         JButton  button  =   new   JButton ( "Click Here" );

         JPanel  panel  =   new   JPanel ( new   FlowLayout ());
        panel . add ( button );
        panel . add ( label );

        button . addActionListener ( new   ActionListener ()   {
                 public   void  actionPerformed ( ActionEvent  e )   {
                    print ( "in actionPerformed()" );
                    label . setText ( "CLICKED!" );
                 }
             });

         JFrame  f  =   new   JFrame ( "SimpleEvent" );
        f . setContentPane ( panel );
        f . setSize ( 300 ,   100 );
        f . setVisible ( true );
     }
}

source/chapter09/SlideShow.java

source/chapter09/SlideShow.java

import  java . awt . * ;
import  java . awt . image . * ;
import  javax . swing . * ;

public   class   SlideShow   extends   JComponent   {
     private   BufferedImage []  slide ;
     private   Dimension  slideSize ;
     private   volatile   int  currSlide ;

     private   Thread  internalThread ;
     private   volatile   boolean  noStopRequested ;

     public   SlideShow ()   {
        currSlide  =   0 ;
        slideSize  =   new   Dimension ( 50 ,   50 );
        buildSlides ();

        setMinimumSize ( slideSize );
        setPreferredSize ( slideSize );
        setMaximumSize ( slideSize );
        setSize ( slideSize );

        noStopRequested  =   true ;
         Runnable  r  =   new   Runnable ()   {
                 public   void  run ()   {
                     try   {
                        runWork ();
                     }   catch   (   Exception  x  )   {
                         // in case ANY exception slips through
                        x . printStackTrace ();  
                     }
                 }
             };

        internalThread  =   new   Thread ( r ,   "SlideShow" );
        internalThread . start ();
     }

     private   void  buildSlides ()   {
         // Request that the drawing be done with anti-aliasing
         // turned on and the quality high.
         RenderingHints  renderHints  =   new   RenderingHints (
             RenderingHints . KEY_ANTIALIASING ,
             RenderingHints . VALUE_ANTIALIAS_ON );

        renderHints . put (
             RenderingHints . KEY_RENDERING ,
             RenderingHints . VALUE_RENDER_QUALITY );

        slide  =   new   BufferedImage [ 20 ];

         Color  rectColor  =   new   Color ( 100 ,   160 ,   250 );     // blue
         Color  circleColor  =   new   Color ( 250 ,   250 ,   150 );   // yellow

         for   (   int  i  =   0 ;  i  <  slide . length ;  i ++   )   {
            slide [ i ]   =   new   BufferedImage (
                    slideSize . width ,
                    slideSize . height ,
                     BufferedImage . TYPE_INT_RGB );

             Graphics2D  g2  =  slide [ i ]. createGraphics ();
            g2 . setRenderingHints ( renderHints );

            g2 . setColor ( rectColor );
            g2 . fillRect ( 0 ,   0 ,  slideSize . width ,  slideSize . height );

            g2 . setColor ( circleColor );

             int  diameter  =   0 ;
             if   (  i  <   (  slide . length  /   2   )   )   {
                diameter  =   5   +   (   8   *  i  );
             }   else   {
                diameter  =   5   +   (   8   *    (  slide . length  -  i  )   );
             }

             int  inset  =   (  slideSize . width  -  diameter  )   /   2 ;
            g2 . fillOval ( inset ,  inset ,  diameter ,  diameter );

            g2 . setColor ( Color . black );
            g2 . drawRect (
                 0 ,   0 ,  slideSize . width  -   1 ,  slideSize . height  -   1 );

            g2 . dispose ();
         }
     }

     public   void  paint ( Graphics  g )   {
        g . drawImage ( slide [ currSlide ],   0 ,   0 ,   this );
     }

     private   void  runWork ()   {
         while   (  noStopRequested  )   {
             try   {
                 Thread . sleep ( 100 );    // 10 frames per second
                
                 // increment the slide pointer
                currSlide  =   (  currSlide  +   1   )   %  slide . length ;

                 // signal the event thread to call paint()
                repaint ();
             }   catch   (   InterruptedException  x  )   {
                 Thread . currentThread (). interrupt ();  
             }
         }
     }

     public   void  stopRequest ()   {
        noStopRequested  =   false ;
        internalThread . interrupt ();
     }

     public   boolean  isAlive ()   {
         return  internalThread . isAlive ();
     }

     public   static   void  main ( String []  args )   {
         SlideShow  ss  =   new   SlideShow ();

         JPanel  p  =   new   JPanel ( new   FlowLayout ());
        p . add ( ss );

         JFrame  f  =   new   JFrame ( "SlideShow Demo" );
        f . setContentPane ( p );
        f . setSize ( 250 ,   150 );
        f . setVisible ( true );
     }
}

source/chapter10/ThreadViewer.java

source/chapter10/ThreadViewer.java

import  java . awt . * ;
import  java . awt . event . * ;
import  javax . swing . * ;
import  javax . swing . table . * ;

public   class   ThreadViewer   extends   JPanel   {
     private   ThreadViewerTableModel  tableModel ;

     public   ThreadViewer ()   {
        tableModel  =   new   ThreadViewerTableModel ();

         JTable  table  =   new   JTable ( tableModel );
        table . setAutoResizeMode ( JTable . AUTO_RESIZE_LAST_COLUMN );

         TableColumnModel  colModel  =  table . getColumnModel ();
         int  numColumns  =  colModel . getColumnCount ();

         // manually size all but the last column
         for   (   int  i  =   0 ;  i  <  numColumns  -   1 ;  i ++   )   {
             TableColumn  col  =  colModel . getColumn ( i );

            col . sizeWidthToFit ();
            col . setPreferredWidth ( col . getWidth ()   +   5 );
            col . setMaxWidth ( col . getWidth ()   +   5 );
         }

         JScrollPane  sp  =   new   JScrollPane ( table );

        setLayout ( new   BorderLayout ());
        add ( sp ,   BorderLayout . CENTER );
     }

     public   void  dispose ()   {
        tableModel . stopRequest ();
     }

     protected   void  finalize ()   throws   Throwable   {
        dispose ();
     }

     public   static   JFrame  createFramedInstance ()   {
         final   ThreadViewer  viewer  =   new   ThreadViewer ();

         final   JFrame  f  =   new   JFrame ( "ThreadViewer" );
        f . addWindowListener ( new   WindowAdapter ()   {
                 public   void  windowClosing ( WindowEvent  e )   {
                    f . setVisible ( false );
                    f . dispose ();
                    viewer . dispose ();
                 }
             });

        f . setContentPane ( viewer );
        f . setSize ( 500 ,   300 );
        f . setVisible ( true );

         return  f ;
     }
    
     public   static   void  main ( String []  args )   {
         JFrame  f  =   ThreadViewer . createFramedInstance ();

         // For this example, exit the VM when the viewer
         // frame is closed.
        f . addWindowListener ( new   WindowAdapter ()   {
                 public   void  windowClosing ( WindowEvent  e )   {
                     System . exit ( 0 );
                 }
             });

         // Keep the main thread from exiting by blocking
         // on wait() for a notification that never comes.
         Object  lock  =   new   Object ();
         synchronized   (  lock  )   {
             try   {
                lock . wait ();
             }   catch   (   InterruptedException  x  )   {
             }
         }
     }
}

source/chapter10/ThreadViewerTableModel.java

source/chapter10/ThreadViewerTableModel.java

import  java . awt . * ;
import  java . lang . reflect . * ;
import  javax . swing . * ;
import  javax . swing . table . * ;

public   class   ThreadViewerTableModel   extends   AbstractTableModel   {
     private   Object  dataLock ;  
     private   int  rowCount ;
     private   Object [][]  cellData ;
     private   Object [][]  pendingCellData ;

     // the column information remains constant
     private   final   int  columnCount ;
     private   final   String []  columnName ;
     private   final   Class []  columnClass ;

     // self-running object control variables
     private   Thread  internalThread ;
     private   volatile   boolean  noStopRequested ;

     public   ThreadViewerTableModel ()   {
        rowCount  =   0 ;
        cellData  =   new   Object [ 0 ][ 0 ];

         // JTable uses this information for the column headers
         String []  names  =   {  
             "Priority" ,   "Alive" ,  
             "Daemon" ,   "Interrupted" ,  
             "ThreadGroup" ,   "Thread Name"   };
        columnName  =  names ;                          
                        
         // JTable uses this information for cell rendering
         Class []  classes  =   {  
             Integer . class ,   Boolean . class ,  
             Boolean . class ,   Boolean . class ,  
             String . class ,   String . class   };
        columnClass  =  classes ;

        columnCount  =  columnName . length ;

         // used to control concurrent access
        dataLock  =   new   Object ();  

        noStopRequested  =   true ;
         Runnable  r  =   new   Runnable ()   {
                 public   void  run ()   {
                     try   {
                        runWork ();
                     }   catch   (   Exception  x  )   {
                         // in case ANY exception slips through
                        x . printStackTrace ();  
                     }
                 }
             };

        internalThread  =   new   Thread ( r ,   "ThreadViewer" );
        internalThread . setPriority ( Thread . MAX_PRIORITY  -   2 );
        internalThread . setDaemon ( true );
        internalThread . start ();
     }

     private   void  runWork ()   {

         // The run() method of transferPending is called by 
         // the event handling thread for safe concurrency.
         Runnable  transferPending  =   new   Runnable ()   {
                 public   void  run ()   {
                    transferPendingCellData ();

                     // Method of AbstractTableModel that 
                     // causes the table to be updated.
                    fireTableDataChanged ();  
                 }
             };

         while   (  noStopRequested  )   {
             try   {
                createPendingCellData ();
                 SwingUtilities . invokeAndWait ( transferPending );
                 Thread . sleep ( 5000 );
             }   catch   (   InvocationTargetException  tx  )   {
                tx . printStackTrace ();
                stopRequest ();
             }   catch   (   InterruptedException  x  )   {
                 Thread . currentThread (). interrupt ();  
             }
         }
     }

     public   void  stopRequest ()   {
        noStopRequested  =   false ;
        internalThread . interrupt ();
     }

     public   boolean  isAlive ()   {
         return  internalThread . isAlive ();
     }

     private   void  createPendingCellData ()   {
         // this method is called by the internal thread
         Thread []  thread  =  findAllThreads ();
         Object [][]  cell  =   new   Object [ thread . length ][ columnCount ];

         for   (   int  i  =   0 ;  i  <  thread . length ;  i ++   )   {
             Thread  t  =  thread [ i ];
             Object []  rowCell  =  cell [ i ];

            rowCell [ 0 ]   =   new   Integer ( t . getPriority ());
            rowCell [ 1 ]   =   new   Boolean ( t . isAlive ());
            rowCell [ 2 ]   =   new   Boolean ( t . isDaemon ());
            rowCell [ 3 ]   =   new   Boolean ( t . isInterrupted ());
            rowCell [ 4 ]   =  t . getThreadGroup (). getName ();
            rowCell [ 5 ]   =  t . getName ();
         }

         synchronized   (  dataLock  )   {
            pendingCellData  =  cell ;
         }
     }

     private   void  transferPendingCellData ()   {
         // this method is called by the event thread
         synchronized   (  dataLock  )   {
            cellData  =  pendingCellData ;
            rowCount  =  cellData . length ;
         }
     }

     public   int  getRowCount ()   {
         // this method is called by the event thread
         return  rowCount ;
     }
    
     public   Object  getValueAt ( int  row ,   int  col )   {
         // this method is called by the event thread
         return  cellData [ row ][ col ];
     }

     public   int  getColumnCount ()   {
         return  columnCount ;
     }

     public   Class  getColumnClass ( int  columnIdx )   {
         return  columnClass [ columnIdx ];
     }

     public   String  getColumnName ( int  columnIdx )   {
         return  columnName [ columnIdx ];
     }

     public   static   Thread []  findAllThreads ()   {
         ThreadGroup  group  =  
             Thread . currentThread (). getThreadGroup ();

         ThreadGroup  topGroup  =  group ;

         // traverse the ThreadGroup tree to the top
         while   (  group  !=   null   )   {
            topGroup  =  group ;
            group  =  group . getParent ();
         }

         // Create a destination array that is about
         // twice as big as needed to be very confident
         // that none are clipped.
         int  estimatedSize  =  topGroup . activeCount ()   *   2 ;
         Thread []  slackList  =   new   Thread [ estimatedSize ];

         // Load the thread references into the oversized
         // array. The actual number of threads loaded 
         // is returned.
         int  actualSize  =  topGroup . enumerate ( slackList );

         // copy into a list that is the exact size
         Thread []  list  =   new   Thread [ actualSize ];
         System . arraycopy ( slackList ,   0 ,  list ,   0 ,  actualSize );

         return  list ;
     }
}

source/chapter11/InnerSelfRun.java

source/chapter11/InnerSelfRun.java

public   class   InnerSelfRun   extends   Object   {
     private   Thread  internalThread ;
     private   volatile   boolean  noStopRequested ;

     public   InnerSelfRun ()   {
         // other constructor stuff should appear here first ...
         System . out . println ( "in constructor - initializing..." );

         // just before returning, the thread should be created and started.
        noStopRequested  =   true ;

         Runnable  r  =   new   Runnable ()   {
                 public   void  run ()   {
                     try   {
                        runWork ();
                     }   catch   (   Exception  x  )   {
                         // in case ANY exception slips through
                        x . printStackTrace ();  
                     }
                 }
             };

        internalThread  =   new   Thread ( r );
        internalThread . start ();
     }

     private   void  runWork ()   {
         while   (  noStopRequested  )   {
             System . out . println ( "in runWork() - still going..." );

             try   {
                 Thread . sleep ( 700 );
             }   catch   (   InterruptedException  x  )   {
                 // Any caught interrupts should be habitually re-asserted
                 // for any blocking statements which follow.
                 Thread . currentThread (). interrupt ();   // re-assert interrupt
             }
         }
     }

     public   void  stopRequest ()   {
        noStopRequested  =   false ;
        internalThread . interrupt ();
     }

     public   boolean  isAlive ()   {
         return  internalThread . isAlive ();
     }
}

source/chapter11/InnerSelfRunMain.java

source/chapter11/InnerSelfRunMain.java

public   class   InnerSelfRunMain   extends   Object   {
     public   static   void  main ( String []  args )   {
         InnerSelfRun  sr  =   new   InnerSelfRun ();

         try   {   Thread . sleep ( 3000 );   }   catch   (   InterruptedException  x  )   {   }

        sr . stopRequest ();
     }
}

source/chapter11/SelfRun.java

source/chapter11/SelfRun.java

public   class   SelfRun   extends   Object   implements   Runnable   {
     private   Thread  internalThread ;
     private   volatile   boolean  noStopRequested ;

     public   SelfRun ()   {
         // other constructor stuff should appear here first ...
         System . out . println ( "in constructor - initializing..." );

         // Just before returning, the thread should be 
         // created and started.
        noStopRequested  =   true ;
        internalThread  =   new   Thread ( this );
        internalThread . start ();
     }

     public   void  run ()   {
         // Check that no one has erroneously invoked 
         // this public method.
         if   (   Thread . currentThread ()   !=  internalThread  )   {
             throw   new   RuntimeException ( "only the internal "   +
                 "thread is allowed to invoke run()" );
         }

         while   (  noStopRequested  )   {
             System . out . println ( "in run() - still going..." );

             try   {
                 Thread . sleep ( 700 );
             }   catch   (   InterruptedException  x  )   {
                 // Any caught interrupts should be habitually 
                 // reasserted for any blocking statements 
                 // which follow.
                 Thread . currentThread (). interrupt ();  
             }
         }
     }

     public   void  stopRequest ()   {
        noStopRequested  =   false ;
        internalThread . interrupt ();
     }

     public   boolean  isAlive ()   {
         return  internalThread . isAlive ();
     }
}

source/chapter11/SelfRunMain.java

source/chapter11/SelfRunMain.java

public   class   SelfRunMain   extends   Object   {
     public   static   void  main ( String []  args )   {
         SelfRun  sr  =   new   SelfRun ();

         try   {   Thread . sleep ( 3000 );   }   catch   (   InterruptedException  x  )   {   }

        sr . stopRequest ();
     }
}

source/chapter11/Squish.java

source/chapter11/Squish.java

import  java . awt . * ;
import  java . awt . image . * ;
import  java . awt . geom . * ;
import  javax . swing . * ;

public   class   Squish   extends   JComponent   {
     private   Image []  frameList ;
     private   long  msPerFrame ;
     private   volatile   int  currFrame ;

     private   Thread  internalThread ;
     private   volatile   boolean  noStopRequested ;

     public   Squish (
                 int  width ,
                 int  height ,
                 long  msPerCycle ,  
                 int  framesPerSec ,  
                 Color  fgColor
             )   {

        setPreferredSize ( new   Dimension ( width ,  height ));

         int  framesPerCycle  =  
                 ( int )   (   (  framesPerSec  *  msPerCycle  )   /   1000   );
        msPerFrame  =   1000L   /  framesPerSec ;

        frameList  =  
            buildImages ( width ,  height ,  fgColor ,  framesPerCycle );
        currFrame  =   0 ;

        noStopRequested  =   true ;
         Runnable  r  =   new   Runnable ()   {
                 public   void  run ()   {
                     try   {
                        runWork ();
                     }   catch   (   Exception  x  )   {
                         // in case ANY exception slips through
                        x . printStackTrace ();  
                     }
                 }
             };

        internalThread  =   new   Thread ( r );
        internalThread . start ();
     }

     private   Image []  buildImages (
                 int  width ,  
                 int  height ,  
                 Color  color ,
                 int  count
             )   {

         BufferedImage []  im  =   new   BufferedImage [ count ];

         for   (   int  i  =   0 ;  i  <  count ;  i ++   )   {
            im [ i ]   =   new   BufferedImage (
                    width ,  height ,   BufferedImage . TYPE_INT_ARGB );

             double  xShape  =   0.0 ;
             double  yShape  =  
                 (   ( double )   (  i  *  height  )   )   /   ( double )  count ;

             double  wShape  =  width ;
             double  hShape  =   2.0   *   (  height  -  yShape  );
             Ellipse2D  shape  =   new   Ellipse2D . Double (
                        xShape ,  yShape ,  wShape ,  hShape );

             Graphics2D  g2  =  im [ i ]. createGraphics ();
            g2 . setColor ( color );
            g2 . fill ( shape );
            g2 . dispose ();
         }

         return  im ;
     }

     private   void  runWork ()   {
         while   (  noStopRequested  )   {
            currFrame  =   (  currFrame  +   1   )   %  frameList . length ;
            repaint ();

             try   {
                 Thread . sleep ( msPerFrame );
             }   catch   (   InterruptedException  x  )   {
                 // reassert interrupt
                 Thread . currentThread (). interrupt ();  
                 // continue on as if sleep completed normally
             }
         }
     }

     public   void  stopRequest ()   {
        noStopRequested  =   false ;
        internalThread . interrupt ();
     }

     public   boolean  isAlive ()   {
         return  internalThread . isAlive ();
     }

     public   void  paint ( Graphics  g )   {
        g . drawImage ( frameList [ currFrame ],   0 ,   0 ,   this );
     }
}

source/chapter11/SquishMain.java

source/chapter11/SquishMain.java

import  java . awt . * ;
import  java . awt . event . * ;
import  javax . swing . * ;

public   class   SquishMain   extends   JPanel   {
     public   SquishMain ()   {
         Squish  blueSquish  =   new   Squish ( 150 ,   150 ,   3000L ,   10 ,   Color . blue );
         Squish  redSquish  =   new   Squish ( 250 ,   200 ,   2500L ,   10 ,   Color . red );

         this . setLayout ( new   FlowLayout ());
         this . add ( blueSquish );
         this . add ( redSquish );
     }

     public   static   void  main ( String []  args )   {
         SquishMain  sm  =   new   SquishMain ();

         JFrame  f  =   new   JFrame ( "Squish Main" );
        f . setContentPane ( sm );
        f . setSize ( 450 ,   250 );
        f . setVisible ( true );
        f . addWindowListener ( new   WindowAdapter ()   {
                 public   void  windowClosing ( WindowEvent  e )   {
                     System . exit ( 0 );
                 }
             });
     }
}

source/chapter12/ExceptionCallback.java

source/chapter12/ExceptionCallback.java

import  java . io . * ;
import  java . util . * ;

public   class   ExceptionCallback   extends   Object   {
     private   Set  exceptionListeners ;
     private   Thread  internalThread ;
     private   volatile   boolean  noStopRequested ;

     public   ExceptionCallback ( ExceptionListener []  initialGroup )   {
        init ( initialGroup );
     }

     public   ExceptionCallback ( ExceptionListener  initialListener )   {
         ExceptionListener []  group  =   new   ExceptionListener [ 1 ];
        group [ 0 ]   =  initialListener ;
        init ( group );
     }

     public   ExceptionCallback ()   {
        init ( null );
     }

     private   void  init ( ExceptionListener []  initialGroup )   {
         System . out . println ( "in constructor - initializing..." );

        exceptionListeners  =  
                 Collections . synchronizedSet ( new   HashSet ());

         // If any listeners should be added before the internal
         // thread starts, add them now.
         if   (  initialGroup  !=   null   )   {
             for   (   int  i  =   0 ;  i  <  initialGroup . length ;  i ++   )   {
                addExceptionListener ( initialGroup [ i ]);
             }
         }

         // Just before returning from the constructor, 
         // the thread should be created and started.
        noStopRequested  =   true ;

         Runnable  r  =   new   Runnable ()   {
                 public   void  run ()   {
                     try   {
                        runWork ();
                     }   catch   (   Exception  x  )   {
                         // in case ANY exception slips through
                        sendException ( x );
                     }
                 }
             };

        internalThread  =   new   Thread ( r );
        internalThread . start ();
     }

     private   void  runWork ()   {
         try   {
            makeConnection ();   // will throw an IOException
         }   catch   (   IOException  x  )   {
            sendException ( x );
             // Probably in a real scenario, a "return" 
             // statement should be here.
         }  

         String  str  =   null ;
         int  len  =  determineLength ( str );   // NullPointerException
     }

     private   void  makeConnection ()   throws   IOException   {
         // A NumberFormatException will be thrown when
         // this String is parsed.
         String  portStr  =   "j20" ;  
         int  port  =   0 ;

         try   {
            port  =   Integer . parseInt ( portStr );
         }   catch   (   NumberFormatException  x  )   {
            sendException ( x );
            port  =   80 ;   // use default;
         }  

        connectToPort ( port );   // will throw an IOException
     }

     private   void  connectToPort ( int  portNum )   throws   IOException   {
         throw   new   IOException ( "connection refused" );
     }

     private   int  determineLength ( String  s )   {
         return  s . length ();
     }

     public   void  stopRequest ()   {
        noStopRequested  =   false ;
        internalThread . interrupt ();
     }

     public   boolean  isAlive ()   {
         return  internalThread . isAlive ();
     }

     private   void  sendException ( Exception  x )   {
         if   (  exceptionListeners . size ()   ==   0   )   {
             // If there aren't any listeners, dump the stack
             // trace to the console.
            x . printStackTrace ();
             return ;
         }

         // Used "synchronized" to make sure that other threads
         // do not make changes to the Set while iterating.
         synchronized   (  exceptionListeners  )   {
             Iterator  iter  =  exceptionListeners . iterator ();
             while   (  iter . hasNext ()   )   {
                 ExceptionListener  l  =  
                         ( ExceptionListener )  iter . next ();

                l . exceptionOccurred ( x ,   this );
             }
         }
     }

     public   void  addExceptionListener ( ExceptionListener  l )   {
         // Silently ignore a request to add a "null" listener.
         if   (  l  !=   null   )   {
             // If a listener was already in the Set, it will
             // silently replace itself so that no duplicates
             // accumulate.
            exceptionListeners . add ( l );
         }
     }

     public   void  removeExceptionListener ( ExceptionListener  l )   {
         // Silently ignore a request to remove a listener
         // that is not in the Set.
        exceptionListeners . remove ( l );
     }

     public   String  toString ()   {
         return  getClass (). getName ()   +  
             "[isAlive()="   +  isAlive ()   +   "]" ;
     }
}

source/chapter12/ExceptionCallbackMain.java

source/chapter12/ExceptionCallbackMain.java

public   class   ExceptionCallbackMain  
         extends   Object  
         implements   ExceptionListener   {

     private   int  exceptionCount ;

     public   ExceptionCallbackMain ()   {
        exceptionCount  =   0 ;
     }

     public   void  exceptionOccurred ( Exception  x ,   Object  source )   {
        exceptionCount ++ ;
         System . err . println ( "EXCEPTION #"   +  exceptionCount  +
                 ", source="   +  source );
        x . printStackTrace ();
     }

     public   static   void  main ( String []  args )   {
         ExceptionListener  xListener  =   new   ExceptionCallbackMain ();
         ExceptionCallback  ec  =   new   ExceptionCallback ( xListener );
     }
}

source/chapter12/ExceptionListener.java

source/chapter12/ExceptionListener.java

public   interface   ExceptionListener   {
     public   void  exceptionOccurred ( Exception  x ,   Object  source );
}

source/chapter13/htmldir/images/five.gif

source/chapter13/htmldir/images/four.gif

source/chapter13/htmldir/images/one.gif

source/chapter13/htmldir/images/three.gif

source/chapter13/htmldir/images/two.gif

source/chapter13/htmldir/index.html

Thread pooling helps to save the VM the work of creating anddestroying threads when they can be easily recycled.
Thread pooling reduces response time since the worker threadis already created, started, and running. It is only waitingfor the signal to go!
Thread pooling holds resource usage to a predetermined, upperlimit. Instead of starting a new thread for every requestreceived by an HTTP server, a set of workers is available to service requests. When this set is being completely used by other requests, the server does not increase its load, but rejects requests until a worker becomes available.
Thread pooling generally works best when a thread is onlyneeded for a brief period of time.
When using the thread pooling technique, care must be takento reasonably ensure that threads don't become deadlocked ordie.

source/chapter13/HttpServer.java

source/chapter13/HttpServer.java

import  java . io . * ;
import  java . net . * ;

// uses ObjectFIFO from chapter 18

public   class   HttpServer   extends   Object   {

     // currently available HttpWorker objects
     private   ObjectFIFO  idleWorkers ;

     // all HttpWorker objects
     private   HttpWorker []  workerList ;
     private   ServerSocket  ss ;

     private   Thread  internalThread ;
     private   volatile   boolean  noStopRequested ;

     public   HttpServer (
                 File  docRoot ,
                 int  port ,
                 int  numberOfWorkers ,
                 int  maxPriority
             )   throws   IOException   {

         // Allow a max of 10 sockets to queue up 
         // waiting for accpet().
        ss  =   new   ServerSocket ( port ,   10 );  

         if   (   (  docRoot  ==   null   )   ||  
              ! docRoot . exists ()   ||  
              ! docRoot . isDirectory ()  
            )   {

             throw   new   IOException ( "specified docRoot is null "   +
                 "or does not exist or is not a directory" );
         }

         // ensure that at least one worker is created
        numberOfWorkers  =   Math . max ( 1 ,  numberOfWorkers );

         // Ensure: 
         // (minAllowed + 2) <= serverPriority <= (maxAllowed - 1)
         // which is generally:
         //   3 <= serverPriority <= 9
         int  serverPriority  =   Math . max (
                 Thread . MIN_PRIORITY  +   2 ,  
                 Math . min ( maxPriority ,   Thread . MAX_PRIORITY  -   1 )
             );

         // Have the workers run at a slightly lower priority so 
         // that new requests are handled with more urgency than 
         // in-progress requests.
         int  workerPriority  =  serverPriority  -   1 ;

        idleWorkers  =   new   ObjectFIFO ( numberOfWorkers );
        workerList  =   new   HttpWorker [ numberOfWorkers ];

         for   (   int  i  =   0 ;  i  <  numberOfWorkers ;  i ++   )   {
             // Workers get a reference to the FIFO to add 
             // themselves back in when they are ready to 
             // handle a new request.
            workerList [ i ]   =   new   HttpWorker (
                        docRoot ,  workerPriority ,  idleWorkers );
         }

         // Just before returning, the thread should be 
         // created and started.
        noStopRequested  =   true ;

         Runnable  r  =   new   Runnable ()   {
                 public   void  run ()   {
                     try   {
                        runWork ();
                     }   catch   (   Exception  x  )   {
                         // in case ANY exception slips through
                        x . printStackTrace ();  
                     }
                 }
             };

        internalThread  =   new   Thread ( r );
        internalThread . setPriority ( serverPriority );  
        internalThread . start ();
     }

     private   void  runWork ()   {
         System . out . println (
                 "HttpServer ready to receive requests" );

         while   (  noStopRequested  )   {
             try   {
                 Socket  s  =  ss . accept ();

                 if   (  idleWorkers . isEmpty ()   )   {
                     System . out . println (
                         "HttpServer too busy, denying request" );

                     BufferedWriter  writer  =  
                         new   BufferedWriter (
                             new   OutputStreamWriter (
                                s . getOutputStream ()));
                    
                    writer . write ( "HTTP/1.0 503 Service "   +
                                     "Unavailable\r\n\r\n" );

                    writer . flush ();
                    writer . close ();
                    writer  =   null ;
                 }   else   {
                     // No need to be worried that idleWorkers 
                     // will suddenly be empty since this is the 
                     // only thread removing items from the queue.
                     HttpWorker  worker  =  
                             ( HttpWorker )  idleWorkers . remove ();

                    worker . processRequest ( s );
                 }
             }   catch   (   IOException  iox  )   {
                 if   (  noStopRequested  )   {
                    iox . printStackTrace ();
                 }
             }   catch   (   InterruptedException  x  )   {
                 // re-assert interrupt
                 Thread . currentThread (). interrupt ();  
             }
         }
     }

     public   void  stopRequest ()   {
        noStopRequested  =   false ;
        internalThread . interrupt ();

         for   (   int  i  =   0 ;  i  <  workerList . length ;  i ++   )   {
            workerList [ i ]. stopRequest ();
         }

         if   (  ss  !=   null   )   {
             try   {  ss . close ();   }   catch   (   IOException  iox  )   {   }
            ss  =   null ;
         }
     }

     public   boolean  isAlive ()   {
         return  internalThread . isAlive ();
     }

     private   static   void  usageAndExit ( String  msg ,   int  exitCode )   {
         System . err . println ( msg );
         System . err . println ( "Usage: java HttpServer <port> "   +
                             "<numWorkers> <documentRoot>" );
         System . err . println ( "   <port> - port to listen on "   +
                             "for HTTP requests" );
         System . err . println ( "   <numWorkers> - number of "   +
                             "worker threads to create" );
         System . err . println ( "   <documentRoot> - base "   +
                             "directory for HTML files" );
         System . exit ( exitCode );
     }

     public   static   void  main ( String []  args )   {
         if   (  args . length  !=   3   )   {
            usageAndExit ( "wrong number of arguments" ,   1 );
         }

         String  portStr  =  args [ 0 ];
         String  numWorkersStr  =  args [ 1 ];
         String  docRootStr  =  args [ 2 ];

         int  port  =   0 ;

         try   {
            port  =   Integer . parseInt ( portStr );
         }   catch   (   NumberFormatException  x  )   {
            usageAndExit ( "could not parse port number from '"   +  
                    portStr  +   "'" ,   2 );
         }

         if   (  port  <   1   )   {
            usageAndExit ( "invalid port number specified: "   +  
                    port ,   3 );
         }

         int  numWorkers  =   0 ;

         try   {
            numWorkers  =   Integer . parseInt ( numWorkersStr );
         }   catch   (   NumberFormatException  x  )   {
            usageAndExit (
                     "could not parse number of workers from '"   +  
                    numWorkersStr  +   "'" ,   4 );
         }

         File  docRoot  =   new   File ( docRootStr );

         try   {
             new   HttpServer ( docRoot ,  port ,  numWorkers ,   6 );
         }   catch   (   IOException  x  )   {
            x . printStackTrace ();
            usageAndExit ( "could not construct HttpServer" ,   5 );
         }
     }
}

source/chapter13/HttpWorker.java

source/chapter13/HttpWorker.java

import  java . io . * ;
import  java . net . * ;
import  java . util . * ;

// uses class ObjectFIFO from chapter 18

public   class   HttpWorker   extends   Object   {
     private   static   int  nextWorkerID  =   0 ;

     private   File  docRoot ;
     private   ObjectFIFO  idleWorkers ;
     private   int  workerID ;
     private   ObjectFIFO  handoffBox ;

     private   Thread  internalThread ;
     private   volatile   boolean  noStopRequested ;

     public   HttpWorker (
                 File  docRoot ,  
                 int  workerPriority ,  
                 ObjectFIFO  idleWorkers
             )   {

         this . docRoot  =  docRoot ;
         this . idleWorkers  =  idleWorkers ;

        workerID  =  getNextWorkerID ();
        handoffBox  =   new   ObjectFIFO ( 1 );   // only one slot

         // Just before returning, the thread should be 
         // created and started.
        noStopRequested  =   true ;

         Runnable  r  =   new   Runnable ()   {
                 public   void  run ()   {
                     try   {
                        runWork ();
                     }   catch   (   Exception  x  )   {
                         // in case ANY exception slips through
                        x . printStackTrace ();  
                     }
                 }
             };

        internalThread  =   new   Thread ( r );
        internalThread . setPriority ( workerPriority );
        internalThread . start ();
     }

     public   static   synchronized   int  getNextWorkerID ()   {  
         // synchronized at the class level to ensure uniqueness
         int  id  =  nextWorkerID ;
        nextWorkerID ++ ;
         return  id ;
     }

     public   void  processRequest ( Socket  s )  
                 throws   InterruptedException   {

        handoffBox . add ( s );
     }

     private   void  runWork ()   {
         Socket  s  =   null ;
         InputStream  in  =   null ;
         OutputStream  out  =   null ;

         while   (  noStopRequested  )   {
             try   {
                 // Worker is ready to receive new service 
                 // requests, so it adds itself to the idle 
                 // worker queue.
                idleWorkers . add ( this );

                 // Wait here until the server puts a request 
                 // into the handoff box.
                s  =   ( Socket )  handoffBox . remove ();

                in  =  s . getInputStream ();
                out  =  s . getOutputStream ();
                generateResponse ( in ,  out );
                out . flush ();
             }   catch   (   IOException  iox  )   {
                 System . err . println (
                     "I/O error while processing request, "   +
                     "ignoring and adding back to idle "   +
                     "queue - workerID="   +  workerID );
             }   catch   (   InterruptedException  x  )   {
                 // re-assert the interrupt
                 Thread . currentThread (). interrupt ();  
             }   finally   {
                 // Try to close everything, ignoring 
                 // any IOExceptions that might occur.
                 if   (  in  !=   null   )   {
                     try   {  
                        in . close ();  
                     }   catch   (   IOException  iox  )   {
                         // ignore
                     }   finally   {
                        in  =   null ;
                     }
                 }

                 if   (  out  !=   null   )   {
                     try   {  
                        out . close ();  
                     }   catch   (   IOException  iox  )   {
                         // ignore
                     }   finally   {
                        out  =   null ;
                     }
                 }

                 if   (  s  !=   null   )   {
                     try   {  
                        s . close ();  
                     }   catch   (   IOException  iox  )   {
                         // ignore
                     }   finally   {
                        s  =   null ;
                     }
                 }
             }
         }
     }

     private   void  generateResponse (
                 InputStream  in ,  
                 OutputStream  out
             )   throws   IOException   {

         BufferedReader  reader  =  
                 new   BufferedReader ( new   InputStreamReader ( in ));

         String  requestLine  =  reader . readLine ();

         if   (   (  requestLine  ==   null   )   ||  
              (  requestLine . length ()   <   1   )  
            )   {

             throw   new   IOException ( "could not read request" );
         }

         System . out . println ( "workerID="   +  workerID  +  
                 ", requestLine="   +  requestLine );

         StringTokenizer  st  =   new   StringTokenizer ( requestLine );
         String  filename  =   null ;

         try   {
             // request method, typically 'GET', but ignored
            st . nextToken ();  

             // the second token should be the filename
            filename  =  st . nextToken ();
         }   catch   (   NoSuchElementException  x  )   {
             throw   new   IOException (
                     "could not parse request line" );
         }

         File  requestedFile  =  generateFile ( filename );

         BufferedOutputStream  buffOut  =  
                 new   BufferedOutputStream ( out );

         if   (  requestedFile . exists ()   )   {
             System . out . println ( "workerID="   +  workerID  +  
                     ", 200 OK: "   +  filename );

             int  fileLen  =   ( int )  requestedFile . length ();

             BufferedInputStream  fileIn  =  
                 new   BufferedInputStream (
                     new   FileInputStream ( requestedFile ));

             // Use this utility to make a guess obout the
             // content type based on the first few bytes 
             // in the stream.
             String  contentType  =  
                 URLConnection . guessContentTypeFromStream (
                    fileIn );

             byte []  headerBytes  =  createHeaderBytes (
                     "HTTP/1.0 200 OK" ,  
                    fileLen ,
                    contentType
                 );

            buffOut . write ( headerBytes );

             byte []  buf  =   new   byte [ 2048 ];
             int  blockLen  =   0 ;

             while   (   (  blockLen  =  fileIn . read ( buf )   )   !=   - 1   )   {
                buffOut . write ( buf ,   0 ,  blockLen );
             }

            fileIn . close ();
         }   else   {
             System . out . println ( "workerID="   +  workerID  +  
                     ", 404 Not Found: "   +  filename  );

             byte []  headerBytes  =  createHeaderBytes (
                     "HTTP/1.0 404 Not Found" ,  
                     - 1 ,
                     null
                 );

            buffOut . write ( headerBytes );
         }

        buffOut . flush ();
     }

     private   File  generateFile ( String  filename )   {
         File  requestedFile  =  docRoot ;   // start at the base

         // Build up the path to the requested file in a 
         // platform independent way. URL's use '/' in their
         // path, but this platform may not.
         StringTokenizer  st  =   new   StringTokenizer ( filename ,   "/" );
         while   (  st . hasMoreTokens ()   )   {
             String  tok  =  st . nextToken ();

             if   (  tok . equals ( ".." )   )   {
                 // Silently ignore parts of path that might
                 // lead out of the document root area.
                 continue ;
             }

            requestedFile  =  
                 new   File ( requestedFile ,  tok );
         }

         if   (  requestedFile . exists ()   &&  
             requestedFile . isDirectory ()  
            )   {

             // If a directory was requested, modify the request
             // to look for the "index.html" file in that
             // directory.
            requestedFile  =  
                 new   File ( requestedFile ,   "index.html" );
         }

         return  requestedFile ;
     }

     private   byte []  createHeaderBytes (
                 String  resp ,  
                 int  contentLen ,
                 String  contentType
             )   throws   IOException   {

         ByteArrayOutputStream  baos  =   new   ByteArrayOutputStream ();
         BufferedWriter  writer  =   new   BufferedWriter (
                 new   OutputStreamWriter ( baos ));

         // Write the first line of the response, followed by
         // the RFC-specified line termination sequence.
        writer . write ( resp  +   "\r\n" );

         // If a length was specified, add it to the header
         if   (  contentLen  !=   - 1   )   {
            writer . write (
                 "Content-Length: "   +  contentLen  +   "\r\n" );
         }

         // If a type was specified, add it to the header
         if   (  contentType  !=   null   )   {
            writer . write (
                 "Content-Type: "   +  contentType  +   "\r\n" );
         }

         // A blank line is required after the header.
        writer . write ( "\r\n" );
        writer . flush ();

         byte []  data  =  baos . toByteArray ();
        writer . close ();

         return  data ;
     }

     public   void  stopRequest ()   {
        noStopRequested  =   false ;
        internalThread . interrupt ();
     }

     public   boolean  isAlive ()   {
         return  internalThread . isAlive ();
     }
}

source/chapter13/ObjectFIFO.java

source/chapter13/ObjectFIFO.java

public   class   ObjectFIFO   extends   Object   {
     private   Object []  queue ;
     private   int  capacity ;
     private   int  size ;
     private   int  head ;
     private   int  tail ;

     public   ObjectFIFO ( int  cap )   {
        capacity  =   (  cap  >   0   )   ?  cap  :   1 ;   // at least 1
        queue  =   new   Object [ capacity ];
        head  =   0 ;
        tail  =   0 ;
        size  =   0 ;
     }

     public   int  getCapacity ()   {
         return  capacity ;
     }

     public   synchronized   int  getSize ()   {
         return  size ;
     }

     public   synchronized   boolean  isEmpty ()   {
         return   (  size  ==   0   );
     }

     public   synchronized   boolean  isFull ()   {
         return   (  size  ==  capacity  );
     }

     public   synchronized   void  add ( Object  obj )  
             throws   InterruptedException   {

        waitWhileFull ();

        queue [ head ]   =  obj ;
        head  =   (  head  +   1   )   %  capacity ;
        size ++ ;

        notifyAll ();   // let any waiting threads know about change
     }

     public   synchronized   void  addEach ( Object []  list )  
             throws   InterruptedException   {

         //
         // You might want to code a more efficient 
         // implementation here ... (see ByteFIFO.java)
         //

         for   (   int  i  =   0 ;  i  <  list . length ;  i ++   )   {
            add ( list [ i ]);
         }
     }

     public   synchronized   Object  remove ()  
             throws   InterruptedException   {

        waitWhileEmpty ();
        
         Object  obj  =  queue [ tail ];

         // don't block GC by keeping unnecessary reference
        queue [ tail ]   =   null ;  

        tail  =   (  tail  +   1   )   %  capacity ;
        size -- ;

        notifyAll ();   // let any waiting threads know about change

         return  obj ;
     }

     public   synchronized   Object []  removeAll ()  
             throws   InterruptedException   {

         //
         // You might want to code a more efficient 
         // implementation here ... (see ByteFIFO.java)
         //

         Object []  list  =   new   Object [ size ];   // use the current size

         for   (   int  i  =   0 ;  i  <  list . length ;  i ++   )   {
            list [ i ]   =  remove ();
         }

         // if FIFO was empty, a zero-length array is returned
         return  list ;  
     }

     public   synchronized   Object []  removeAtLeastOne ()  
             throws   InterruptedException   {

        waitWhileEmpty ();   // wait for a least one to be in FIFO
         return  removeAll ();
     }

     public   synchronized   boolean  waitUntilEmpty ( long  msTimeout )  
             throws   InterruptedException   {

         if   (  msTimeout  ==   0L   )   {
            waitUntilEmpty ();    // use other method
             return   true ;
         }

         // wait only for the specified amount of time
         long  endTime  =   System . currentTimeMillis ()   +  msTimeout ;
         long  msRemaining  =  msTimeout ;

         while   (   ! isEmpty ()   &&   (  msRemaining  >   0L   )   )   {
            wait ( msRemaining );
            msRemaining  =  endTime  -   System . currentTimeMillis ();
         }

         // May have timed out, or may have met condition, 
         // calc return value.
         return  isEmpty ();
     }

     public   synchronized   void  waitUntilEmpty ()  
             throws   InterruptedException   {

         while   (   ! isEmpty ()   )   {
            wait ();
         }
     }

     public   synchronized   void  waitWhileEmpty ()  
             throws   InterruptedException   {

         while   (  isEmpty ()   )   {
            wait ();
         }
     }

     public   synchronized   void  waitUntilFull ()  
             throws   InterruptedException   {

         while   (   ! isFull ()   )   {
            wait ();
         }
     }

     public   synchronized   void  waitWhileFull ()  
             throws   InterruptedException   {

         while   (  isFull ()   )   {
            wait ();
         }
     }
}

source/chapter13/ThreadPool.java

source/chapter13/ThreadPool.java

// uses ObjectFIFO from chapter 18

public   class   ThreadPool   extends   Object   {
     private   ObjectFIFO  idleWorkers ;
     private   ThreadPoolWorker []  workerList ;

     public   ThreadPool ( int  numberOfThreads )   {
         // make sure that it's at least one
        numberOfThreads  =   Math . max ( 1 ,  numberOfThreads );

        idleWorkers  =   new   ObjectFIFO ( numberOfThreads );
        workerList  =   new   ThreadPoolWorker [ numberOfThreads ];

         for   (   int  i  =   0 ;  i  <  workerList . length ;  i ++   )   {
            workerList [ i ]   =   new   ThreadPoolWorker ( idleWorkers );
         }
     }

     public   void  execute ( Runnable  target )   throws   InterruptedException   {
         // block (forever) until a worker is available
         ThreadPoolWorker  worker  =   ( ThreadPoolWorker )  idleWorkers . remove ();
        worker . process ( target );
     }

     public   void  stopRequestIdleWorkers ()   {
         try   {
             Object []  idle  =  idleWorkers . removeAll ();
             for   (   int  i  =   0 ;  i  <  idle . length ;  i ++   )   {
                 (   ( ThreadPoolWorker )  idle [ i ]   ). stopRequest ();
             }
         }   catch   (   InterruptedException  x  )   {
             Thread . currentThread (). interrupt ();   // re-assert
         }
     }

     public   void  stopRequestAllWorkers ()   {
         // Stop the idle one's first since that won't interfere with anything
         // productive.
        stopRequestIdleWorkers ();

         // give the idle workers a quick chance to die 
         try   {   Thread . sleep ( 250 );   }   catch   (   InterruptedException  x  )   {   }
        
         // Step through the list of ALL workers that are still alive.
         for   (   int  i  =   0 ;  i  <  workerList . length ;  i ++   )   {
             if   (  workerList [ i ]. isAlive ()   )   {
                workerList [ i ]. stopRequest ();
             }
         }
     }
}

source/chapter13/ThreadPoolMain.java

source/chapter13/ThreadPoolMain.java

public   class   ThreadPoolMain   extends   Object   {

     public   static   Runnable  makeRunnable (
                 final   String  name ,  
                 final   long  firstDelay
             )   {

         return   new   Runnable ()   {
                 public   void  run ()   {
                     try   {
                         System . out . println ( name  + ": starting up" );
                         Thread . sleep ( firstDelay );
                         System . out . println ( name  +   ": doing some stuff" );
                         Thread . sleep ( 2000 );
                         System . out . println ( name  +   ": leaving" );
                     }   catch   (   InterruptedException  ix  )   {
                         System . out . println ( name  +   ": got interrupted!" );
                         return ;
                     }   catch   (   Exception  x  )   {
                        x . printStackTrace ();
                     }
                 }

                 public   String  toString ()   {
                     return  name ;
                 }
             };
     }

     public   static   void  main ( String []  args )   {
         try   {
             ThreadPool  pool  =   new   ThreadPool ( 3 );

             Runnable  ra  =  makeRunnable ( "RA" ,   3000 );
            pool . execute ( ra );

             Runnable  rb  =  makeRunnable ( "RB" ,   1000 );
            pool . execute ( rb );

             Runnable  rc  =  makeRunnable ( "RC" ,   2000 );
            pool . execute ( rc );

             Runnable  rd  =  makeRunnable ( "RD" ,   60000 );
            pool . execute ( rd );

             Runnable  re  =  makeRunnable ( "RE" ,   1000 );
            pool . execute ( re );

            pool . stopRequestIdleWorkers ();
             Thread . sleep ( 2000 );
            pool . stopRequestIdleWorkers ();

             Thread . sleep ( 5000 );
            pool . stopRequestAllWorkers ();
         }   catch   (   InterruptedException  ix  )   {
            ix . printStackTrace ();
         }
     }
}

source/chapter13/ThreadPoolWorker.java

source/chapter13/ThreadPoolWorker.java

// uses class ObjectFIFO from chapter 18

public   class   ThreadPoolWorker   extends   Object   {
     private   static   int  nextWorkerID  =   0 ;

     private   ObjectFIFO  idleWorkers ;
     private   int  workerID ;
     private   ObjectFIFO  handoffBox ;

     private   Thread  internalThread ;
     private   volatile   boolean  noStopRequested ;

     public   ThreadPoolWorker ( ObjectFIFO  idleWorkers )   {
         this . idleWorkers  =  idleWorkers ;

        workerID  =  getNextWorkerID ();
        handoffBox  =   new   ObjectFIFO ( 1 );   // only one slot

         // just before returning, the thread should be created and started.
        noStopRequested  =   true ;

         Runnable  r  =   new   Runnable ()   {
                 public   void  run ()   {
                     try   {
                        runWork ();
                     }   catch   (   Exception  x  )   {
                         // in case ANY exception slips through
                        x . printStackTrace ();  
                     }
                 }
             };

        internalThread  =   new   Thread ( r );
        internalThread . start ();
     }

     public   static   synchronized   int  getNextWorkerID ()   {  
         // notice: synchronized at the class level to ensure uniqueness
         int  id  =  nextWorkerID ;
        nextWorkerID ++ ;
         return  id ;
     }

     public   void  process ( Runnable  target )   throws   InterruptedException   {
        handoffBox . add ( target );
     }

     private   void  runWork ()   {
         while   (  noStopRequested  )   {
             try   {
                 System . out . println ( "workerID="   +  workerID  +  
                         ", ready for work" );
                 // Worker is ready work. This will never block since the
                 // idleWorker FIFO queue has enough capacity for all of
                 // the workers.
                idleWorkers . add ( this );

                 // wait here until the server puts a request into the box
                 Runnable  r  =   ( Runnable )  handoffBox . remove ();

                 System . out . println ( "workerID="   +  workerID  +  
                         ", starting execution of new Runnable: "   +  r );
                runIt ( r );   // catches all exceptions
             }   catch   (   InterruptedException  x  )   {
                 Thread . currentThread (). interrupt ();   // re-assert
             }
         }
     }

     private   void  runIt ( Runnable  r )   {
         try   {
            r . run ();
         }   catch   (   Exception  runex  )   {
             // catch any and all exceptions 
             System . err . println ( "Uncaught exception fell through from run()" );
            runex . printStackTrace ();
         }   finally   {
             // Clear the interrupted flag (in case it comes back set)
             // so that if the loop goes again, the 
             // handoffBox.remove() does not mistakenly throw
             // an InterruptedException.
             Thread . interrupted ();
         }
     }

     public   void  stopRequest ()   {
         System . out . println ( "workerID="   +  workerID  +  
                 ", stopRequest() received." );
        noStopRequested  =   false ;
        internalThread . interrupt ();
     }

     public   boolean  isAlive ()   {
         return  internalThread . isAlive ();
     }
}

source/chapter14/EarlyReturn.java

source/chapter14/EarlyReturn.java

public   class   EarlyReturn   extends   Object   {
     private   volatile   int  value ;

     public   EarlyReturn ( int  initialValue )   {
        value  =  initialValue ;
     }

     public   synchronized   void  setValue ( int  newValue )   {
         if   (  value  !=  newValue  )   {
            value  =  newValue ;
            notifyAll ();
         }
     }

     public   synchronized   boolean  waitUntilAtLeast (
                 int  minValue ,
                 long  msTimeout
             )   throws   InterruptedException   {

         System . out . println ( "entering waitUntilAtLeast() - "   +
                 "value="   +  value  +
                 ",minValue="   +  minValue );

         if   (  value  <  minValue  )   {
            wait ( msTimeout );
         }

         System . out . println ( "leaving waitUntilAtLeast() - "   +  
                 "value="   +  value  +
                 ",minValue="   +  minValue );

         // May have timed out, or may have met value, 
         // calc return value.
         return   (  value  >=  minValue  );
     }

     public   static   void  main ( String []  args )   {
         try   {
             final   EarlyReturn  er  =   new   EarlyReturn ( 0 );

             Runnable  r  =   new   Runnable ()   {
                     public   void  run ()   {
                         try   {
                             Thread . sleep ( 1500 );
                            er . setValue ( 2 );
                             Thread . sleep ( 500 );
                            er . setValue ( 3 );
                             Thread . sleep ( 500 );
                            er . setValue ( 4 );
                         }   catch   (   Exception  x  )   {
                            x . printStackTrace ();
                         }
                     }
                 };

             Thread  t  =   new   Thread ( r );
            t . start ();

             System . out . println (
                     "about to: waitUntilAtLeast(5, 3000)" );
             long  startTime  =   System . currentTimeMillis ();
             boolean  retVal  =  er . waitUntilAtLeast ( 5 ,   3000 );
             long  elapsedTime  =  
                     System . currentTimeMillis ()   -  startTime ;

             System . out . println ( "after "   +  elapsedTime  +  
                     " ms, retVal="   +  retVal );
         }   catch   (   InterruptedException  ix  )   {
            ix . printStackTrace ();
         }
     }
}

source/chapter14/EarlyReturnFix.java

source/chapter14/EarlyReturnFix.java

public   class   EarlyReturnFix   extends   Object   {
     private   volatile   int  value ;

     public   EarlyReturnFix ( int  initialValue )   {
        value  =  initialValue ;
     }

     public   synchronized   void  setValue ( int  newValue )   {
         if   (  value  !=  newValue  )   {
            value  =  newValue ;
            notifyAll ();
         }
     }

     public   synchronized   boolean  waitUntilAtLeast (
                 int  minValue ,
                 long  msTimeout
             )   throws   InterruptedException   {

         System . out . println ( "entering waitUntilAtLeast() - "   +  
                 "value="   +  value  +   ",minValue="   +  minValue );

         long  endTime  =   System . currentTimeMillis ()   +  msTimeout ;
         long  msRemaining  =  msTimeout ;

         while   (   (  value  <  minValue  )   &&   (  msRemaining  >   0L   )   )   {
             System . out . println ( "in waitUntilAtLeast() - "   +  
                     "about to: wait("   +  msRemaining  +   ")" );
            wait ( msRemaining );
            msRemaining  =  endTime  -   System . currentTimeMillis ();
             System . out . println ( "in waitUntilAtLeast() - "   +
                     "back from wait(), new msRemaining="   +
                    msRemaining );
         }

         System . out . println ( "leaving waitUntilAtLeast() - "   +
                 "value="   +  value  +   ",minValue="   +  minValue );

         // May have timed out, or may have met value, 
         // calc return value.
         return   (  value  >=  minValue  );
     }

     public   static   void  main ( String []  args )   {
         try   {
             final   EarlyReturnFix  er  =   new   EarlyReturnFix ( 0 );

             Runnable  r  =   new   Runnable ()   {
                     public   void  run ()   {
                         try   {
                             Thread . sleep ( 1500 );
                            er . setValue ( 2 );
                             Thread . sleep ( 500 );
                            er . setValue ( 3 );
                             Thread . sleep ( 500 );
                            er . setValue ( 4 );
                         }   catch   (   Exception  x  )   {
                            x . printStackTrace ();
                         }
                     }
                 };

             Thread  t  =   new   Thread ( r );
            t . start ();

             System . out . println (
                     "about to: waitUntilAtLeast(5, 3000)" );
             long  startTime  =   System . currentTimeMillis ();
             boolean  retVal  =  er . waitUntilAtLeast ( 5 ,   3000 );
             long  elapsedTime  =  
                     System . currentTimeMillis ()   -  startTime ;

             System . out . println ( "after "   +  elapsedTime  +  
                     " ms, retVal="   +  retVal );
         }   catch   (   InterruptedException  ix  )   {
            ix . printStackTrace ();
         }
     }
}

source/chapter14/FullWait.java

source/chapter14/FullWait.java

public   class   FullWait   extends   Object   {
     private   volatile   int  value ;

     public   FullWait ( int  initialValue )   {
        value  =  initialValue ;
     }

     public   synchronized   void  setValue ( int  newValue )   {
         if   (  value  !=  newValue  )   {
            value  =  newValue ;
            notifyAll ();
         }
     }

     public   synchronized   boolean  waitUntilAtLeast (
                 int  minValue ,
                 long  msTimeout
             )   throws   InterruptedException   {

         if   (  msTimeout  ==   0L   )   {
             while   (  value  <  minValue  )   {
                wait ();    // wait indefinitely until notified
             }

             // condition has finally been met
             return   true ;
         }  

         // only wait for the specified amount of time
         long  endTime  =   System . currentTimeMillis ()   +  msTimeout ;
         long  msRemaining  =  msTimeout ;

         while   (   (  value  <  minValue  )   &&   (  msRemaining  >   0L   )   )   {
            wait ( msRemaining );
            msRemaining  =  endTime  -   System . currentTimeMillis ();
         }

         // May have timed out, or may have met value, 
         // calc return value.
         return   (  value  >=  minValue  );
     }

     public   String  toString ()   {
         return  getClass (). getName ()   +   "[value="   +  value  +   "]" ;
     }
}

source/chapter14/FullWaitMain.java

source/chapter14/FullWaitMain.java

public   class   FullWaitMain   extends   Object   {
     private   FullWait  fullwait ;
     private   Thread  internalThread ;
     private   volatile   boolean  noStopRequested ;

     public   FullWaitMain ( FullWait  fw )   {
        fullwait  =  fw ;

        noStopRequested  =   true ;
         Runnable  r  =   new   Runnable ()   {
                 public   void  run ()   {
                     try   {
                        runWork ();
                     }   catch   (   Exception  x  )   {
                        x . printStackTrace ();  
                     }
                 }
             };

        internalThread  =   new   Thread ( r );
        internalThread . start ();
     }

     private   void  runWork ()   {
         int  count  =   6 ;

         while   (  noStopRequested  )   {
            fullwait . setValue ( count );
             System . out . println ( "just set value to "   +  count );
            count ++ ;

             try   {
                 Thread . sleep ( 1000 );
             }   catch   (   InterruptedException  x  )   {
                 // reassert interrupt
                 Thread . currentThread (). interrupt ();
             }
         }
     }

     public   void  stopRequest ()   {
        noStopRequested  =   false ;
        internalThread . interrupt ();
     }

     public   boolean  isAlive ()   {
         return  internalThread . isAlive ();
     }

     public   static   void  waitfor ( FullWait  fw ,   int  val ,   long  limit )  
                 throws   InterruptedException   {

         System . out . println ( "about to waitUntilAtLeast("   +  
                val  +   ", "   +  limit  +   ") ... " );

         long  startTime  =   System . currentTimeMillis ();
         boolean  retVal  =  fw . waitUntilAtLeast ( val ,  limit );
         long  endTime  =   System . currentTimeMillis ();

         System . out . println ( "waited for "   +  
                 (  endTime  -  startTime  )   +  
                 " ms, retVal="   +  retVal  +   "\n---------------" );
     }

     public   static   void  main ( String []  args )   {
         try   {
             FullWait  fw  =   new   FullWait ( 5 );
             FullWaitMain  fwm  =   new   FullWaitMain ( fw );

             Thread . sleep ( 500 );

             // should return true before 10 seconds
            waitfor ( fw ,   10 ,   10000L );  

             // should return true right away --already >= 6
            waitfor ( fw ,   6 ,   5000L );

             // should return true right away
             //   --already >= 6 (negative time ignored)
            waitfor ( fw ,   6 ,   - 1000L );

             // should return false right away --not there 
             // yet & negative time
            waitfor ( fw ,   15 ,   - 1000L );

             // should return false after 5 seconds
            waitfor ( fw ,   999 ,   5000L );

             // should eventually return true
            waitfor ( fw ,   20 ,   0L );

            fwm . stopRequest ();
         }   catch   (   InterruptedException  x  )   {
             System . err . println ( "*unexpectedly* interrupted "   +
                     "somewhere in main()" );
         }
     }
}

source/chapter15/BufferedThreadedInputStream.java

source/chapter15/BufferedThreadedInputStream.java

import  java . io . * ;

// uses ThreadedInputStream

public   class   BufferedThreadedInputStream  
         extends   FilterInputStream   {

     // fixed class that does *not* have a synchronized close()
     private   static   class   BISFix   extends   BufferedInputStream   {
         public   BISFix ( InputStream  rawIn ,   int  buffSize )   {
             super ( rawIn ,  buffSize );
         }

         public   void  close ()   throws   IOException   {
             if   (  in  !=   null   )   {
                 try   {
                    in . close ();
                 }   finally   {
                    in  =   null ;
                 }
             }
         }
     }

     public   BufferedThreadedInputStream (
                 InputStream  rawIn ,  
                 int  bufferSize
             )   {

         super ( rawIn );   // super-class' "in" is set below

         // rawIn -> BufferedIS -> ThreadedIS -> 
         //       BufferedIS -> read()

         BISFix  bis  =   new   BISFix ( rawIn ,  bufferSize );
         ThreadedInputStream  tis  =  
                 new   ThreadedInputStream ( bis ,  bufferSize );

         // Change the protected variable 'in' from the 
         // superclass from rawIn to the correct stream.
        in  =   new   BISFix ( tis ,  bufferSize );
     }

     public   BufferedThreadedInputStream ( InputStream  rawIn )   {
         this ( rawIn ,   2048 );
     }

     // Overridden to show that InterruptedIOException might 
     // be thrown.
     public   int  read ()  
             throws   InterruptedIOException ,   IOException   {

         return  in . read ();
     }

     // Overridden to show that InterruptedIOException might 
     // be thrown.
     public   int  read ( byte []  b )  
             throws   InterruptedIOException ,   IOException   {

         return  in . read ( b );
     }

     // Overridden to show that InterruptedIOException might 
     // be thrown.
     public   int  read ( byte []  b ,   int  off ,   int  len )  
             throws   InterruptedIOException ,   IOException   {

         return  in . read ( b ,  off ,  len );
     }

     // Overridden to show that InterruptedIOException might 
     // be thrown.
     public   long  skip ( long  n )  
             throws   InterruptedIOException ,   IOException   {

         return  in . skip ( n );
     }

     // The remainder of the methods are directly inherited from 
     // FilterInputStream and access "in" in the much the same 
     // way as the methods above do.
}

source/chapter15/ByteFIFO.java

source/chapter15/ByteFIFO.java

public   class   ByteFIFO   extends   Object   {
     private   byte []  queue ;
     private   int  capacity ;
     private   int  size ;
     private   int  head ;
     private   int  tail ;

     public   ByteFIFO ( int  cap )   {
        capacity  =   (  cap  >   0   )   ?  cap  :   1 ;   // at least 1
        queue  =   new   byte [ capacity ];
        head  =   0 ;
        tail  =   0 ;
        size  =   0 ;
     }

     public   int  getCapacity ()   {
         return  capacity ;
     }

     public   synchronized   int  getSize ()   {
         return  size ;
     }

     public   synchronized   boolean  isEmpty ()   {
         return   (  size  ==   0   );
     }

     public   synchronized   boolean  isFull ()   {
         return   (  size  ==  capacity  );
     }

     public   synchronized   void  add ( byte  b )  
             throws   InterruptedException   {

        waitWhileFull ();

        queue [ head ]   =  b ;
        head  =   (  head  +   1   )   %  capacity ;
        size ++ ;

        notifyAll ();   // let any waiting threads know about change
     }

     public   synchronized   void  add ( byte []  list )  
             throws   InterruptedException   {

         // For efficiency, the bytes are copied in blocks
         // instead of one at a time. As space becomes available,
         // more bytes are copied until all of them have been
         // added.

         int  ptr  =   0 ;

         while   (  ptr  <  list . length  )   {
             // If full, the lock will be released to allow 
             // another thread to come in and remove bytes.
            waitWhileFull ();

             int  space  =  capacity  -  size ;
             int  distToEnd  =  capacity  -  head ;
             int  blockLen  =   Math . min ( space ,  distToEnd );

             int  bytesRemaining  =  list . length  -  ptr ;
             int  copyLen  =   Math . min ( blockLen ,  bytesRemaining );

             System . arraycopy ( list ,  ptr ,  queue ,  head ,  copyLen );
            head  =   (  head  +  copyLen  )   %  capacity ;
            size  +=  copyLen ;
            ptr  +=  copyLen ;

             // Keep the lock, but let any waiting threads 
             // know that something has changed.
            notifyAll ();
         }
     }

     public   synchronized   byte  remove ()  
             throws   InterruptedException   {

        waitWhileEmpty ();
        
         byte  b  =  queue [ tail ];
        tail  =   (  tail  +   1   )   %  capacity ;
        size -- ;

        notifyAll ();   // let any waiting threads know about change

         return  b ;
     }

     public   synchronized   byte []  removeAll ()   {
         // For efficiency, the bytes are copied in blocks
         // instead of one at a time. 

         if   (  isEmpty ()   )   {
             // Nothing to remove, return a zero-length
             // array and do not bother with notification
             // since nothing was removed.
             return   new   byte [ 0 ];  
         }

         // based on the current size
         byte []  list  =   new   byte [ size ];  

         // copy in the block from tail to the end
         int  distToEnd  =  capacity  -  tail ;
         int  copyLen  =   Math . min ( size ,  distToEnd );
         System . arraycopy ( queue ,  tail ,  list ,   0 ,  copyLen );

         // If data wraps around, copy the remaining data
         // from the front of the array.
         if   (  size  >  copyLen  )   {
             System . arraycopy (
                    queue ,   0 ,  list ,  copyLen ,  size  -  copyLen );
         }

        tail  =   (  tail  +  size  )   %  capacity ;
        size  =   0 ;   // everything has been removed

         // Signal any and all waiting threads that 
         // something has changed.
        notifyAll ();  

         return  list ;  
     }

     public   synchronized   byte []  removeAtLeastOne ()  
             throws   InterruptedException   {

        waitWhileEmpty ();   // wait for a least one to be in FIFO
         return  removeAll ();
     }

     public   synchronized   boolean  waitUntilEmpty ( long  msTimeout )  
             throws   InterruptedException   {

         if   (  msTimeout  ==   0L   )   {
            waitUntilEmpty ();    // use other method
             return   true ;
         }

         // wait only for the specified amount of time
         long  endTime  =   System . currentTimeMillis ()   +  msTimeout ;
         long  msRemaining  =  msTimeout ;

         while   (   ! isEmpty ()   &&   (  msRemaining  >   0L   )   )   {
            wait ( msRemaining );
            msRemaining  =  endTime  -   System . currentTimeMillis ();
         }

         // May have timed out, or may have met condition, 
         // calc return value.
         return  isEmpty ();
     }

     public   synchronized   void  waitUntilEmpty ()  
             throws   InterruptedException   {

         while   (   ! isEmpty ()   )   {
            wait ();
         }
     }

     public   synchronized   void  waitWhileEmpty ()  
             throws   InterruptedException   {

         while   (  isEmpty ()   )   {
            wait ();
         }
     }

     public   synchronized   void  waitUntilFull ()  
             throws   InterruptedException   {

         while   (   ! isFull ()   )   {
            wait ();
         }
     }

     public   synchronized   void  waitWhileFull ()  
             throws   InterruptedException   {

         while   (  isFull ()   )   {
            wait ();
         }
     }
}

source/chapter15/CalcClient.java

source/chapter15/CalcClient.java

import  java . io . * ;
import  java . net . * ;

public   class   CalcClient   extends   Object   {
     public   static   void  main ( String []  args )   {
         String  hostname  =   "localhost" ;
         int  port  =   2001 ;

         try   {
             Socket  sock  =   new   Socket ( hostname ,  port );

             DataInputStream  in  =   new   DataInputStream (
                 new   BufferedInputStream ( sock . getInputStream ()));
             DataOutputStream  out  =   new   DataOutputStream (
                 new   BufferedOutputStream ( sock . getOutputStream ()));

             double  val  =   4.0 ;
            out . writeDouble ( val );
            out . flush ();

             double  sqrt  =  in . readDouble ();
             System . out . println ( "sent up "   +  val  +   ", got back "   +  sqrt );

             // Don't ever send another request, but stay alive in
             // this eternally blocked state.
             Object  lock  =   new   Object ();
             while   (   true   )   {
                 synchronized   (  lock  )   {
                    lock . wait ();
                 }
             }
         }   catch   (   Exception  x  )   {
            x . printStackTrace ();
         }
     }
}

source/chapter15/CalcServer.java

source/chapter15/CalcServer.java

import  java . io . * ;
import  java . net . * ;
import  java . util . * ;

public   class   CalcServer   extends   Object   {
     private   ServerSocket  ss ;
     private   List  workerList ;
    
     private   Thread  internalThread ;
     private   volatile   boolean  noStopRequested ;

     public   CalcServer ( int  port )   throws   IOException   {
        ss  =   new   ServerSocket ( port );
        workerList  =   new   LinkedList ();

        noStopRequested  =   true ;
         Runnable  r  =   new   Runnable ()   {
                 public   void  run ()   {
                     try   {
                        runWork ();
                     }   catch   (   Exception  x  )   {
                         // in case ANY exception slips through
                        x . printStackTrace ();  
                     }
                 }
             };

        internalThread  =   new   Thread ( r );
        internalThread . start ();
     }

     private   void  runWork ()   {
         System . out . println (
                 "in CalcServer - ready to accept connections" );

         while   (  noStopRequested  )   {
             try   {
                 System . out . println (
                         "in CalcServer - about to block "   +
                         "waiting for a new connection" );
                 Socket  sock  =  ss . accept ();
                 System . out . println (
                     "in CalcServer - received new connection" );
                workerList . add ( new   CalcWorker ( sock ));
             }   catch   (   IOException  iox  )   {
                 if   (  noStopRequested  )   {
                    iox . printStackTrace ();
                 }
             }
         }

         // stop all the workers that were created
         System . out . println ( "in CalcServer - putting in a "   +
                 "stop request to all the workers" );
         Iterator  iter  =  workerList . iterator ();
         while   (  iter . hasNext ()   )   {
             CalcWorker  worker  =   ( CalcWorker )  iter . next ();
            worker . stopRequest ();
         }

         System . out . println ( "in CalcServer - leaving runWork()" );
     }

     public   void  stopRequest ()   {
         System . out . println (
                 "in CalcServer - entering stopRequest()" );
        noStopRequested  =   false ;
        internalThread . interrupt ();

         if   (  ss  !=   null   )   {
             try   {
                ss . close ();
             }   catch   (   IOException  x  )   {
                 // ignore
             }   finally   {
                ss  =   null ;
             }
         }
     }

     public   boolean  isAlive ()   {
         return  internalThread . isAlive ();
     }

     public   static   void  main ( String []  args )   {
         int  port  =   2001 ;

         try   {
             CalcServer  server  =   new   CalcServer ( port );
             Thread . sleep ( 15000 );
            server . stopRequest ();
         }   catch   (   IOException  x  )   {
            x . printStackTrace ();
         }   catch   (   InterruptedException  x  )   {
             // ignore
         }
     }
}

source/chapter15/CalcServerTwo.java

source/chapter15/CalcServerTwo.java

import  java . io . * ;
import  java . net . * ;
import  java . util . * ;

public   class   CalcServerTwo   extends   Object   {
     private   ServerSocket  ss ;
     private   List  workerList ;
    
     private   Thread  internalThread ;
     private   volatile   boolean  noStopRequested ;

     public   CalcServerTwo ( int  port )   throws   IOException   {
        ss  =   new   ServerSocket ( port );
        workerList  =   new   LinkedList ();

        noStopRequested  =   true ;
         Runnable  r  =   new   Runnable ()   {
                 public   void  run ()   {
                     try   {
                        runWork ();
                     }   catch   (   Exception  x  )   {
                         // in case ANY exception slips through
                        x . printStackTrace ();  
                     }
                 }
             };

        internalThread  =   new   Thread ( r );
        internalThread . start ();
     }

     private   void  runWork ()   {
         System . out . println (
                 "in CalcServer - ready to accept connections" );

         while   (  noStopRequested  )   {
             try   {
                 System . out . println (
                         "in CalcServer - about to block "   +
                         "waiting for a new connection" );
                 Socket  sock  =  ss . accept ();
                 System . out . println (
                     "in CalcServer - received new connection" );
                workerList . add ( new   CalcWorkerTwo ( sock ));
             }   catch   (   IOException  iox  )   {
                 if   (  noStopRequested  )   {
                    iox . printStackTrace ();
                 }
             }
         }

         // stop all the workers that were created
         System . out . println ( "in CalcServer - putting in a "   +
                 "stop request to all the workers" );
         Iterator  iter  =  workerList . iterator ();
         while   (  iter . hasNext ()   )   {
             CalcWorkerTwo  worker  =   ( CalcWorkerTwo )  iter . next ();
            worker . stopRequest ();
         }

         System . out . println ( "in CalcServer - leaving runWork()" );
     }

     public   void  stopRequest ()   {
         System . out . println (
                 "in CalcServer - entering stopRequest()" );
        noStopRequested  =   false ;
        internalThread . interrupt ();

         if   (  ss  !=   null   )   {
             try   {
                ss . close ();
             }   catch   (   IOException  x  )   {
                 // ignore
             }   finally   {
                ss  =   null ;
             }
         }
     }

     public   boolean  isAlive ()   {
         return  internalThread . isAlive ();
     }

     public   static   void  main ( String []  args )   {
         int  port  =   2001 ;

         try   {
             CalcServerTwo  server  =   new   CalcServerTwo ( port );
             Thread . sleep ( 15000 );
            server . stopRequest ();
         }   catch   (   IOException  x  )   {
            x . printStackTrace ();
         }   catch   (   InterruptedException  x  )   {
             // ignore
         }
     }
}

source/chapter15/CalcWorker.java

source/chapter15/CalcWorker.java

import  java . io . * ;
import  java . net . * ;

public   class   CalcWorker   extends   Object   {
     private   InputStream  sockIn ;
     private   OutputStream  sockOut ;
     private   DataInputStream  dataIn ;
     private   DataOutputStream  dataOut ;
    
     private   Thread  internalThread ;
     private   volatile   boolean  noStopRequested ;

     public   CalcWorker ( Socket  sock )   throws   IOException   {
        sockIn  =  sock . getInputStream ();
        sockOut  =  sock . getOutputStream ();

        dataIn  =   new   DataInputStream (
                 new   BufferedInputStream ( sockIn ));
        dataOut  =   new   DataOutputStream (
                 new   BufferedOutputStream ( sockOut ));

        noStopRequested  =   true ;
         Runnable  r  =   new   Runnable ()   {
                 public   void  run ()   {
                     try   {
                        runWork ();
                     }   catch   (   Exception  x  )   {
                         // in case ANY exception slips through
                        x . printStackTrace ();  
                     }
                 }
             };

        internalThread  =   new   Thread ( r );
        internalThread . start ();
     }

     private   void  runWork ()   {
         while   (  noStopRequested  )   {
             try   {
                 System . out . println ( "in CalcWorker - about to "   +
                         "block waiting to read a double" );
                 double  val  =  dataIn . readDouble ();
                 System . out . println (
                         "in CalcWorker - read a double!" );
                dataOut . writeDouble ( Math . sqrt ( val ));
                dataOut . flush ();
             }   catch   (   IOException  x  )   {
                 if   (  noStopRequested  )   {
                    x . printStackTrace ();
                    stopRequest ();
                 }
             }
         }

         // In real-world code, be sure to close other streams and
         // the socket as part of the clean-up. Omitted here for
         // brevity.

         System . out . println ( "in CalcWorker - leaving runWork()" );
     }

     public   void  stopRequest ()   {
         System . out . println (
                 "in CalcWorker - entering stopRequest()" );
        noStopRequested  =   false ;
        internalThread . interrupt ();

         if   (  sockIn  !=   null   )   {
             try   {
                sockIn . close ();
             }   catch   (   IOException  iox  )   {
                 // ignore
             }   finally   {
                sockIn  =   null ;
             }
         }

         System . out . println (
                 "in CalcWorker - leaving stopRequest()" );
     }

     public   boolean  isAlive ()   {
         return  internalThread . isAlive ();
     }
}

source/chapter15/CalcWorkerTwo.java

source/chapter15/CalcWorkerTwo.java

import  java . io . * ;
import  java . net . * ;

public   class   CalcWorkerTwo   extends   Object   {
     private   DataInputStream  dataIn ;
     private   DataOutputStream  dataOut ;
    
     private   Thread  internalThread ;
     private   volatile   boolean  noStopRequested ;

     public   CalcWorkerTwo ( Socket  sock )   throws   IOException   {
        dataIn  =   new   DataInputStream (
             new   BufferedThreadedInputStream (
                sock . getInputStream ()));
        dataOut  =   new   DataOutputStream (
             new   BufferedOutputStream (
                sock . getOutputStream ()));

        noStopRequested  =   true ;
         Runnable  r  =   new   Runnable ()   {
                 public   void  run ()   {
                     try   {
                        runWork ();
                     }   catch   (   Exception  x  )   {
                         // in case ANY exception slips through
                        x . printStackTrace ();  
                     }
                 }
             };

        internalThread  =   new   Thread ( r );
        internalThread . start ();
     }

     private   void  runWork ()   {
         while   (  noStopRequested  )   {
             try   {
                 System . out . println ( "in CalcWorker - about to "   +
                         "block waiting to read a double" );
                 double  val  =  dataIn . readDouble ();
                 System . out . println (
                         "in CalcWorker - read a double!" );
                dataOut . writeDouble ( Math . sqrt ( val ));
                dataOut . flush ();
             }   catch   (   InterruptedIOException  iiox  )   {
                 System . out . println ( "in CalcWorker - blocked "   +
                         "read was interrupted!!!" );
             }   catch   (   IOException  x  )   {
                 if   (  noStopRequested  )   {
                    x . printStackTrace ();
                    stopRequest ();
                 }
             }
         }

         // In real-world code, be sure to close other streams 
         // and the socket as part of the clean-up. Omitted here 
         // for brevity.

         System . out . println ( "in CalcWorker - leaving runWork()" );
     }

     public   void  stopRequest ()   {
         System . out . println (
                 "in CalcWorker - entering stopRequest()" );
        noStopRequested  =   false ;
        internalThread . interrupt ();
         System . out . println (
                 "in CalcWorker - leaving stopRequest()" );
     }

     public   boolean  isAlive ()   {
         return  internalThread . isAlive ();
     }
}

source/chapter15/DefiantStream.java

source/chapter15/DefiantStream.java

import  java . io . * ;

public   class   DefiantStream   extends   Object   {
     public   static   void  main ( String []  args )   {
         final   InputStream  in  =   System . in ;

         Runnable  r  =   new   Runnable ()   {
                 public   void  run ()   {
                     try   {
                         System . err . println (
                                 "about to try to read from in" );
                        in . read ();
                         System . err . println ( "just read from in" );
                     }   catch   (   InterruptedIOException  iiox  )   {
                        iiox . printStackTrace ();
                     }   catch   (   IOException  iox  )   {
                        iox . printStackTrace ();
                     //} catch ( InterruptedException ix ) { 
                     //  InterruptedException is never thrown!
                     //  ix.printStackTrace();
                     }   catch   (   Exception  x  )   {
                        x . printStackTrace ();
                     }   finally   {
                         Thread  currThread  =  
                                 Thread . currentThread ();
                         System . err . println ( "inside finally:\n"   +
                             "  currThread="   +  currThread  +   "\n"   +
                             "  currThread.isAlive()="   +  
                            currThread . isAlive ());
                     }
                 }
             };
        
         Thread  t  =   new   Thread ( r );
        t . start ();

         try   {   Thread . sleep ( 2000 );   }  
         catch   (   InterruptedException  x  )   {   }

         System . err . println ( "about to interrupt thread" );
        t . interrupt ();
         System . err . println ( "just interrupted thread" );

         try   {   Thread . sleep ( 2000 );   }  
         catch   (   InterruptedException  x  )   {   }

         System . err . println ( "about to stop thread" );
         // stop() is being used here to show that the extreme
         // action of stopping a thread is also ineffective. 
         // Because stop() is deprecated, the compiler issues
         // a warning.
        t . stop ();  
         System . err . println ( "just stopped thread, t.isAlive()="   +
                t . isAlive ());

         try   {   Thread . sleep ( 2000 );   }  
         catch   (   InterruptedException  x  )   {   }

         System . err . println ( "t.isAlive()="   +  t . isAlive ());
         System . err . println ( "leaving main()" );
     }
}

source/chapter15/SureStop.java

source/chapter15/SureStop.java

import  java . util . * ;

public   class   SureStop   extends   Object   {
     // nested internal class for stop request entries
     private   static   class   Entry   extends   Object   {
         private   Thread  thread ;
         private   long  stopTime ;

         private   Entry ( Thread  t ,   long  stop )   {
            thread  =  t ;
            stopTime  =  stop ;
         }
     }

     // static reference to the singleton instance
     private   static   SureStop  ss ;

     static   {
         // When class is loaded, create exactly one instance 
         // using the private constructor.
        ss  =   new   SureStop ();
     }

     private   List  stopList ;
     private   List  pendingList ;
     private   Thread  internalThread ;

     private   SureStop ()   {
         // using a linked list for fast deletions
        stopList  =   new   LinkedList ();

         // Enough initial capacity for 20 pending additions, 
         // will grow automatically if necessary to keep 
         // ensureStop() from blocking.
        pendingList  =   new   ArrayList ( 20 );

         Runnable  r  =   new   Runnable ()   {
                 public   void  run ()   {
                     try   {
                        runWork ();
                     }   catch   (   Exception  x  )   {
                         // in case ANY exception slips through
                        x . printStackTrace ();  
                     }
                 }
             };

        internalThread  =   new   Thread ( r );
        internalThread . setDaemon ( true );   // no need to run alone
        internalThread . setPriority ( Thread . MAX_PRIORITY );   // high
        internalThread . start ();
     }

     private   void  runWork ()   {
         try   {
             while   (   true   )   {
                 // Since this is a super-high priority thread, 
                 // be sure to give other threads a chance to 
                 // run each time through in case the wait on 
                 // pendingList is very short.
                 Thread . sleep ( 500 );

                 // Stop expired threads and determine the 
                 // amount of time until the next thread is
                 // due to expire.
                 long  sleepTime  =  checkStopList ();

                 synchronized   (  pendingList  )   {
                     if   (  pendingList . size ()   <   1   )   {
                        pendingList . wait ( sleepTime );
                     }

                     if   (  pendingList . size ()   >   0   )   {
                         // Copy into stopList and then remove 
                         // from pendingList.
                        stopList . addAll ( pendingList );
                        pendingList . clear ();
                     }
                 }
             }   // while
         }   catch   (   InterruptedException  x  )   {
             // ignore
         }   catch   (   Exception  x  )   {
             // Never expect this, but print a trace in case 
             // it happens.
            x . printStackTrace ();
         }
     }

     private   long  checkStopList ()   {
         // called from runWork() by the internal thread 

         long  currTime  =   System . currentTimeMillis ();
         long  minTime  =   Long . MAX_VALUE ;

         Iterator  iter  =  stopList . iterator ();
         while   (  iter . hasNext ()   )   {
             Entry  entry  =   ( Entry )  iter . next ();

             if   (  entry . thread . isAlive ()   )   {
                 if   (  entry . stopTime  <  currTime  )   {
                     // timed out, stop it abruptly right now
                     try   {
                        entry . thread . stop ();
                     }   catch   (   SecurityException  x  )   {
                         // Catch this here so that other 
                         // operations are not disrupted. Warn
                         // that thread could not be stopped.
                         System . err . println (
                             "SureStop was not permitted to "   +
                             "stop thread="   +  entry . thread );
                        x . printStackTrace ();
                     }

                     // Since it has stopped, remove it 
                     // from stopList.
                    iter . remove ();
                 }   else   {
                     // Not yet expired, check to see if this 
                     // is the new minimum.
                    minTime  =   Math . min ( entry . stopTime ,  minTime );
                 }
             }   else   {
                 // Thread died on its own, remove it from 
                 // stopList.
                iter . remove ();
             }   // if alive
         }   // while

         long  sleepTime  =  minTime  -   System . currentTimeMillis ();

         // ensure that it is a least a little bit of time
        sleepTime  =   Math . max ( 50 ,  sleepTime );  

         return  sleepTime ;
     }

     private   void  addEntry ( Entry  entry )   {
         // called from ensureStop() by external thread

         synchronized   (  pendingList  )   {
            pendingList . add ( entry );

             // no need for notifyAll(), one waiter
            pendingList . notify ();  
         }
     }

     public   static   void  ensureStop ( Thread  t ,   long  msGracePeriod )   {
         if   (   ! t . isAlive ()   )   {
             // thread is already stopped, return right away
             return ;
         }

         long  stopTime  =  
                 System . currentTimeMillis ()   +  msGracePeriod ;

         Entry  entry  =   new   Entry ( t ,  stopTime );
        ss . addEntry ( entry );
     }
}

source/chapter15/ThreadedInputStream.java

source/chapter15/ThreadedInputStream.java

import  java . io . * ;

// uses SureStop from chapter 16
// uses ByteFIFO from chapter 18

public   class   ThreadedInputStream   extends   FilterInputStream   {
     private   ByteFIFO  buffer ;

     private   volatile   boolean  closeRequested ;
     private   volatile   boolean  eofDetected ;
     private   volatile   boolean  ioxDetected ;
     private   volatile   String  ioxMessage ;

     private   Thread  internalThread ;
     private   volatile   boolean  noStopRequested ;

     public   ThreadedInputStream ( InputStream  in ,   int  bufferSize )   {
         super ( in );

        buffer  =   new   ByteFIFO ( bufferSize );

        closeRequested  =   false ;
        eofDetected  =   false ;
        ioxDetected  =   false ;
        ioxMessage  =   null ;

        noStopRequested  =   true ;
         Runnable  r  =   new   Runnable ()   {
                 public   void  run ()   {
                     try   {
                        runWork ();
                     }   catch   (   Exception  x  )   {
                         // in case ANY exception slips through
                        x . printStackTrace ();  
                     }
                 }
             };

        internalThread  =   new   Thread ( r );
        internalThread . setDaemon ( true );
        internalThread . start ();
     }

     public   ThreadedInputStream ( InputStream  in )   {
         this ( in ,   2048 );
     }

     private   void  runWork ()   {
         byte []  workBuf  =   new   byte [ buffer . getCapacity ()];

         try   {
             while   (  noStopRequested  )   {
                 int  readCount  =  in . read ( workBuf );

                 if   (  readCount  ==   - 1   )   {
                    signalEOF ();
                    stopRequest ();
                 }   else   if   (  readCount  >   0   )   {
                    addToBuffer ( workBuf ,  readCount );
                 }
             }
         }   catch   (   IOException  iox  )   {
             if   (   ! closeRequested  )   {
                ioxMessage  =  iox . getMessage ();
                signalIOX ();
             }
         }   catch   (   InterruptedException  x  )   {
             // ignore
         }   finally   {
             // no matter what, make sure that eofDetected is set
            signalEOF ();
         }
     }

     private   void  signalEOF ()   {
         synchronized   (  buffer  )   {
            eofDetected  =   true ;
            buffer . notifyAll ();
         }
     }

     private   void  signalIOX ()   {
         synchronized   (  buffer  )   {
            ioxDetected  =   true ;
            buffer . notifyAll ();
         }
     }
    
     private   void  signalClose ()   {
         synchronized   (  buffer  )   {
            closeRequested  =   true ;
            buffer . notifyAll ();
         }
     }

     private   void  addToBuffer ( byte []  workBuf ,   int  readCount )  
             throws   InterruptedException   {

         // Create an array exactly as large as the number of
         // bytes read and copy the data into it.
         byte []  addBuf  =   new   byte [ readCount ];
         System . arraycopy ( workBuf ,   0 ,  addBuf ,   0 ,  addBuf . length );

        buffer . add ( addBuf );
     }

     private   void  stopRequest ()   {
         if   (  noStopRequested  )   {
            noStopRequested  =   false ;
            internalThread . interrupt ();
         }
     }

     public   void  close ()   throws   IOException   {
         if   (  closeRequested  )   {
             // already closeRequested, just return
             return ;
         }
        signalClose ();

         SureStop . ensureStop ( internalThread ,   10000 );
        stopRequest ();

         // Use a new thread to close "in" in case it blocks
         final   InputStream  localIn  =  in ;
         Runnable  r  =   new   Runnable ()   {
                 public   void  run ()   {
                     try   {
                        localIn . close ();
                     }   catch   (   IOException  iox  )   {
                         // ignore
                     }
                 }
             };

         Thread  t  =   new   Thread ( r ,   "in-close" );
         // give up when all other non-daemon threads die
        t . setDaemon ( true );   
        t . start ();
     }

     private   void  throwExceptionIfClosed ()   throws   IOException   {
         if   (  closeRequested  )   {
             throw   new   IOException ( "stream is closed" );
         }
     }

     // Throws InterruptedIOException if the thread blocked on
     // read() is interrupted while waiting for data to arrive.
     public   int  read ()  
             throws   InterruptedIOException ,   IOException   {

         // Using read(byte[]) to keep code in one place --makes
         // single-byte read less efficient, but simplifies 
         // the coding.
         byte []  data  =   new   byte [ 1 ];
         int  ret  =  read ( data ,   0 ,   1 );

         if   (  ret  !=   1   )   {
             return   - 1 ;
         }

         return  data [ 0 ]   &   0x000000FF ;
     }

     // Throws InterruptedIOException if the thread blocked on
     // read() is interrupted while waiting for data to arrive.
     public   int  read ( byte []  dest )  
             throws   InterruptedIOException ,   IOException   {

         return  read ( dest ,   0 ,  dest . length );
     }

     // Throws InterruptedIOException if the thread blocked on
     // read() is interrupted while waiting for data to arrive.
     public   int  read (
                 byte []  dest ,  
                 int  offset ,  
                 int  length
             )   throws   InterruptedIOException ,   IOException   {

        throwExceptionIfClosed ();

         if   (  length  <   1   )   {
             return   0 ;
         }

         if   (   (  offset  <   0   )   ||  
              (   (  offset  +  length  )   >  dest . length  )  
            )   {

             throw   new   IllegalArgumentException (
                 "offset must be at least 0, and "   +
                 "(offset + length) must be less than or "   +
                 "equal to dest.length. "   +
                 "offset="   +  offset  +  
                 ", (offset + length )="   +   (  offset  +  length  )   +
                 ", dest.length="   +  dest . length );
         }

         byte []  data  =  removeUpTo ( length );

         if   (  data . length  >   0   )   {
             System . arraycopy ( data ,   0 ,  dest ,  offset ,  data . length );
             return  data . length ;
         }

         // no data
         if   (  eofDetected  )   {
             return   - 1 ;
         }

         // no data and not end of file, must be exception
        stopRequest ();

         if   (  ioxMessage  ==   null   )   {
            ioxMessage  =   "stream cannot be read" ;
         }

         throw   new   IOException ( ioxMessage );
     }

     private   byte []  removeUpTo ( int  maxRead )   throws   IOException   {
         // Convenience method to assist read(byte[], int, int).
         // Waits until at least one byte is ready, EOF is 
         // detected,  an IOException is thrown, or the 
         // stream is closed.
         try   {
             synchronized   (  buffer  )   {
                 while   (  buffer . isEmpty ()   &&  
                         ! eofDetected  &&  
                         ! ioxDetected  &&
                         ! closeRequested
                       )   {
    
                    buffer . wait ();
                 }
    
                 // If stream was closed while waiting, 
                 // get out right away.
                throwExceptionIfClosed ();
    
                 // Ignore eof and exception flags for now, see 
                 // if any data remains.
                 byte []  data  =  buffer . removeAll ();
    
                 if   (  data . length  >  maxRead  )   {
                     // Pulled out too many bytes, 
                     // put excess back.
                     byte []  putBackData  =  
                             new   byte [ data . length  -  maxRead ];
                     System . arraycopy ( data ,  maxRead ,  
                            putBackData ,   0 ,  putBackData . length );
                    buffer . add ( putBackData );
    
                     byte []  keepData  =   new   byte [ maxRead ];
                     System . arraycopy ( data ,   0 ,  
                            keepData ,   0 ,  keepData . length );
                    data  =  keepData ;
                 }
    
                 return  data ;
             }
         }   catch   (   InterruptedException  ix  )   {
             // convert to an IOException
             throw   new   InterruptedIOException ( "interrupted "   +
                 "while waiting for data to arrive for reading" );
         }
     }

     public   long  skip ( long  n )   throws   IOException   {
        throwExceptionIfClosed ();

         if   (  n  <=   0   )   {
             return   0 ;
         }

         int  skipLen  =   ( int )   Math . min ( n ,   Integer . MAX_VALUE );
         int  readCount  =  read ( new   byte [ skipLen ]);

         if   (  readCount  <   0   )   {
             return   0 ;
         }

         return  readCount ;
     }

     public   int  available ()   throws   IOException   {
        throwExceptionIfClosed ();
         return  buffer . getSize ();
     }

     public   boolean  markSupported ()   {
         return   false ;
     }

     public   synchronized   void  mark ( int  readLimit )   {
         // ignore method calls, mark not supported
     }

     public   synchronized   void  reset ()   throws   IOException   {
         throw   new   IOException (
                 "mark-reset not supported on this stream" );
     }
}

source/chapter16/SureStop.java

source/chapter16/SureStop.java

import  java . util . * ;

public   class   SureStop   extends   Object   {
     // nested internal class for stop request entries
     private   static   class   Entry   extends   Object   {
         private   Thread  thread ;
         private   long  stopTime ;

         private   Entry ( Thread  t ,   long  stop )   {
            thread  =  t ;
            stopTime  =  stop ;
         }
     }

     // static reference to the singleton instance
     private   static   SureStop  ss ;

     static   {
         // When class is loaded, create exactly one instance 
         // using the private constructor.
        ss  =   new   SureStop ();
     }

     private   List  stopList ;
     private   List  pendingList ;
     private   Thread  internalThread ;

     private   SureStop ()   {
         // using a linked list for fast deletions
        stopList  =   new   LinkedList ();

         // Enough initial capacity for 20 pending additions, 
         // will grow automatically if necessary to keep 
         // ensureStop() from blocking.
        pendingList  =   new   ArrayList ( 20 );

         Runnable  r  =   new   Runnable ()   {
                 public   void  run ()   {
                     try   {
                        runWork ();
                     }   catch   (   Exception  x  )   {
                         // in case ANY exception slips through
                        x . printStackTrace ();  
                     }
                 }
             };

        internalThread  =   new   Thread ( r );
        internalThread . setDaemon ( true );   // no need to run alone
        internalThread . setPriority ( Thread . MAX_PRIORITY );   // high
        internalThread . start ();
     }

     private   void  runWork ()   {
         try   {
             while   (   true   )   {
                 // Since this is a super-high priority thread, 
                 // be sure to give other threads a chance to 
                 // run each time through in case the wait on 
                 // pendingList is very short.
                 Thread . sleep ( 500 );

                 // Stop expired threads and determine the 
                 // amount of time until the next thread is
                 // due to expire.
                 long  sleepTime  =  checkStopList ();

                 synchronized   (  pendingList  )   {
                     if   (  pendingList . size ()   <   1   )   {
                        pendingList . wait ( sleepTime );
                     }

                     if   (  pendingList . size ()   >   0   )   {
                         // Copy into stopList and then remove 
                         // from pendingList.
                        stopList . addAll ( pendingList );
                        pendingList . clear ();
                     }
                 }
             }   // while
         }   catch   (   InterruptedException  x  )   {
             // ignore
         }   catch   (   Exception  x  )   {
             // Never expect this, but print a trace in case 
             // it happens.
            x . printStackTrace ();
         }
     }

     private   long  checkStopList ()   {
         // called from runWork() by the internal thread 

         long  currTime  =   System . currentTimeMillis ();
         long  minTime  =   Long . MAX_VALUE ;

         Iterator  iter  =  stopList . iterator ();
         while   (  iter . hasNext ()   )   {
             Entry  entry  =   ( Entry )  iter . next ();

             if   (  entry . thread . isAlive ()   )   {
                 if   (  entry . stopTime  <  currTime  )   {
                     // timed out, stop it abruptly right now
                     try   {
                        entry . thread . stop ();
                     }   catch   (   SecurityException  x  )   {
                         // Catch this here so that other 
                         // operations are not disrupted. Warn
                         // that thread could not be stopped.
                         System . err . println (
                             "SureStop was not permitted to "   +
                             "stop thread="   +  entry . thread );
                        x . printStackTrace ();
                     }

                     // Since it has stopped, remove it 
                     // from stopList.
                    iter . remove ();
                 }   else   {
                     // Not yet expired, check to see if this 
                     // is the new minimum.
                    minTime  =   Math . min ( entry . stopTime ,  minTime );
                 }
             }   else   {
                 // Thread died on its own, remove it from 
                 // stopList.
                iter . remove ();
             }   // if alive
         }   // while

         long  sleepTime  =  minTime  -   System . currentTimeMillis ();

         // ensure that it is a least a little bit of time
        sleepTime  =   Math . max ( 50 ,  sleepTime );  

         return  sleepTime ;
     }

     private   void  addEntry ( Entry  entry )   {
         // called from ensureStop() by external thread

         synchronized   (  pendingList  )   {
            pendingList . add ( entry );

             // no need for notifyAll(), one waiter
            pendingList . notify ();  
         }
     }

     public   static   void  ensureStop ( Thread  t ,   long  msGracePeriod )   {
         if   (   ! t . isAlive ()   )   {
             // thread is already stopped, return right away
             return ;
         }

         long  stopTime  =  
                 System . currentTimeMillis ()   +  msGracePeriod ;

         Entry  entry  =   new   Entry ( t ,  stopTime );
        ss . addEntry ( entry );
     }
}

source/chapter16/SureStopDemo.java

source/chapter16/SureStopDemo.java

public   class   SureStopDemo   extends   Object   {
     private   static   Thread  launch (
                 final   String  name ,  
                 long  lifeTime
             )   {

         final   int  loopCount  =   ( int )   (  lifeTime  /   1000   );

         Runnable  r  =   new   Runnable ()   {
                 public   void  run ()   {
                     try   {
                         for   (   int  i  =   0 ;  i  <  loopCount ;  i ++   )   {
                             Thread . sleep ( 1000 );
                             System . out . println (
                                     "-> Running - "   +  name );
                         }
                     }   catch   (   InterruptedException  x  )   {
                         // ignore
                     }
                 }
             };
        
         Thread  t  =   new   Thread ( r );
        t . setName ( name );
        t . start ();

         return  t ;
     }

     public   static   void  main ( String []  args )   {
         Thread  t0  =  launch ( "T0" ,   1000 );
         Thread  t1  =  launch ( "T1" ,   5000 );
         Thread  t2  =  launch ( "T2" ,   15000 );

         try   {   Thread . sleep ( 2000 );   }  
         catch   (   InterruptedException  x  )   {   }

         SureStopVerbose . ensureStop ( t0 ,    9000 );
         SureStopVerbose . ensureStop ( t1 ,   10000 );
         SureStopVerbose . ensureStop ( t2 ,   12000 );

         try   {   Thread . sleep ( 20000 );   }  
         catch   (   InterruptedException  x  )   {   }

         Thread  t3  =  launch ( "T3" ,   15000 );
         SureStopVerbose . ensureStop ( t3 ,   5000 );

         try   {   Thread . sleep ( 1000 );   }  
         catch   (   InterruptedException  x  )   {   }

         Thread  t4  =  launch ( "T4" ,   15000 );
         SureStopVerbose . ensureStop ( t4 ,   3000 );
     }
}

source/chapter16/SureStopVerbose.java

source/chapter16/SureStopVerbose.java

import  java . util . * ;

public   class   SureStopVerbose   extends   Object   {
     // nested internal class for stop request entries
     private   static   class   Entry   extends   Object   {
         private   Thread  thread ;
         private   long  stopTime ;

         private   Entry ( Thread  t ,   long  stop )   {
            thread  =  t ;
            stopTime  =  stop ;
         }
     }

     // static reference to the singleton instance
     private   static   SureStopVerbose  ss ;

     static   {
         // When class is loaded, create exactly one instance 
         // using the private constructor.
        ss  =   new   SureStopVerbose ();
        print ( "SureStopVerbose instance created." );
     }

     private   List  stopList ;
     private   List  pendingList ;
     private   Thread  internalThread ;

     private   SureStopVerbose ()   {
         // using a linked list for fast deletions
        stopList  =   new   LinkedList ();

         // Enough initial capacity for 20 pending additions, 
         // will grow automatically if necessary to keep 
         // ensureStop() from blocking.
        pendingList  =   new   ArrayList ( 20 );

         Runnable  r  =   new   Runnable ()   {
                 public   void  run ()   {
                     try   {
                        runWork ();
                     }   catch   (   Exception  x  )   {
                         // in case ANY exception slips through
                        x . printStackTrace ();  
                     }
                 }
             };

        internalThread  =   new   Thread ( r );
        internalThread . setDaemon ( true );   // no need to run alone
        internalThread . setPriority ( Thread . MAX_PRIORITY );   // high
        internalThread . start ();
     }

     private   void  runWork ()   {
         try   {
             while   (   true   )   {
                 // Since this is a super-high priority thread, 
                 // be sure to give other threads a chance to 
                 // run each time through in case the wait on 
                 // pendingList is very short.
                print ( "about to sleep for 0.5 seconds" );
                 Thread . sleep ( 500 );
                print ( "done with sleep for 0.5 seconds" );

                 long  sleepTime  =  checkStopList ();
                print ( "back from checkStopList(), sleepTime="   +  
                        sleepTime );

                 synchronized   (  pendingList  )   {
                     if   (  pendingList . size ()   <   1   )   {
                        print ( "about to wait on pendingList "   +
                             "for "   +  sleepTime  +   " ms" );
                         long  start  =   System . currentTimeMillis ();
                        pendingList . wait ( sleepTime );
                         long  elapsedTime  =  
                             System . currentTimeMillis ()   -  start ;
                        print ( "waited on pendingList for "   +  
                            elapsedTime  +   " ms" );
                     }


                     if   (  pendingList . size ()   >   0   )   {
                         // copy into stopList and then remove 
                         // from pendingList.
                        print ( "copying "   +  pendingList . size ()   +  
                             " elements from pendingList to "   +
                             "stopList" );
                         int  oldSize  =  stopList . size ();
                        stopList . addAll ( pendingList );
                        pendingList . clear ();
                         int  newSize  =  stopList . size ();
                        print ( "pendingList.size()="   +  
                            pendingList . size ()   +
                             ", stopList grew by "   +  
                             ( newSize  -  oldSize ));
                     }
                 }
             }   // while
         }   catch   (   InterruptedException  x  )   {
             // ignore
         }   catch   (   Exception  x  )   {
             // Never expect this, but print a trace in case 
             // it happens.
            x . printStackTrace ();
         }
     }

     private   long  checkStopList ()   {
        print ( "entering checkStopList() - stopList.size()="   +  
                stopList . size ());
         long  currTime  =   System . currentTimeMillis ();
         long  minTime  =   Long . MAX_VALUE ;

         Iterator  iter  =  stopList . iterator ();
         while   (  iter . hasNext ()   )   {
             Entry  entry  =   ( Entry )  iter . next ();

             if   (  entry . thread . isAlive ()   )   {
                print ( "thread is alive - "   +  
                        entry . thread . getName ());
                 if   (  entry . stopTime  <  currTime  )   {
                     // timed out, stop it abruptly right now
                    print ( "timed out, stopping - "   +  
                            entry . thread . getName ());
                     try   {
                        entry . thread . stop ();
                     }   catch   (   SecurityException  x  )   {
                         // Catch this here so that other 
                         // operations are not disrupted. Warn 
                         // that thread could not be stopped.
                         System . err . println (
                             "SureStop was not permitted to "   +
                             "stop thread="   +  entry . thread );
                        x . printStackTrace ();
                     }

                     // Since it's stopped, remove it 
                     // from stopList.
                    iter . remove ();
                 }   else   {
                     // Not yet expired, check to see if this 
                     // is the new minimum.
                    minTime  =   Math . min ( entry . stopTime ,  minTime );
                    print ( "new minTime="   +  minTime );
                 }
             }   else   {
                print ( "thread died on its own - "   +  
                        entry . thread . getName ());
                 // Thread died on its own, remove it from 
                 // stopList.
                iter . remove ();
             }   // if alive
         }   // while

         long  sleepTime  =  minTime  -   System . currentTimeMillis ();

         // ensure that it is a least a little bit of time
        sleepTime  =   Math . max ( 50 ,  sleepTime );  

        print ( "leaving checkStopList() - stopList.size()="   +  
                stopList . size ());
         return  sleepTime ;
     }

     private   void  addEntry ( Entry  entry )   {
         synchronized   (  pendingList  )   {
            pendingList . add ( entry );

             // no need for notifyAll(), one waiter
            pendingList . notify ();  
            print ( "added entry to pendingList, name="   +  
                entry . thread . getName ()   +  
                 ", stopTime="   +  entry . stopTime  +   ", in "   +  
                 (  entry . stopTime  -   System . currentTimeMillis ()   )   +
                 " ms" );
         }
     }

     public   static   void  ensureStop ( Thread  t ,   long  msGracePeriod )   {
        print ( "entering ensureStop() - name="   +  t . getName ()   +
             ", msGracePeriod="   +  msGracePeriod );

         if   (   ! t . isAlive ()   )   {
             // thread is already stopped, return right away
            print ( "already stopped, not added to list - "   +  
                    t . getName ());
             return ;
         }

         long  stopTime  =  
                 System . currentTimeMillis ()   +  msGracePeriod ;
         Entry  entry  =   new   Entry ( t ,  stopTime );
        ss . addEntry ( entry );
        print ( "leaving ensureStop() - name="   +  t . getName ());
     }

     private   static   void  print ( String  msg )   {
         Thread  t  =   Thread . currentThread ();
         String  name  =  t . getName ();
         if   (  t  ==  ss . internalThread  )   {
            name  =   "SureStopThread" ;
         }

         System . out . println ( name  +   ": "   +  msg );
     }
}

source/chapter17/BooleanLock.java

source/chapter17/BooleanLock.java

public   class   BooleanLock   extends   Object   {
     private   boolean  value ;

     public   BooleanLock ( boolean  initialValue )   {
        value  =  initialValue ;
     }

     public   BooleanLock ()   {
         this ( false );
     }

     public   synchronized   void  setValue ( boolean  newValue )   {
         if   (  newValue  !=  value  )   {
            value  =  newValue ;
            notifyAll ();
         }
     }

     public   synchronized   boolean  waitToSetTrue ( long  msTimeout )  
             throws   InterruptedException   {

         boolean  success  =  waitUntilFalse ( msTimeout );
         if   (  success  )   {
            setValue ( true );
         }

         return  success ;
     }

     public   synchronized   boolean  waitToSetFalse ( long  msTimeout )  
             throws   InterruptedException   {

         boolean  success  =  waitUntilTrue ( msTimeout );
         if   (  success  )   {
            setValue ( false );
         }

         return  success ;
     }

     public   synchronized   boolean  isTrue ()   {
         return  value ;
     }

     public   synchronized   boolean  isFalse ()   {
         return   ! value ;
     }

     public   synchronized   boolean  waitUntilTrue ( long  msTimeout )  
             throws   InterruptedException   {

         return  waitUntilStateIs ( true ,  msTimeout );
     }

     public   synchronized   boolean  waitUntilFalse ( long  msTimeout )  
             throws   InterruptedException   {

         return  waitUntilStateIs ( false ,  msTimeout );
     }

     public   synchronized   boolean  waitUntilStateIs (
                 boolean  state ,  
                 long  msTimeout
             )   throws   InterruptedException   {

         if   (  msTimeout  ==   0L   )   {
             while   (  value  !=  state  )   {
                wait ();    // wait indefinitely until notified
             }

             // condition has finally been met
             return   true ;
         }  

         // only wait for the specified amount of time
         long  endTime  =   System . currentTimeMillis ()   +  msTimeout ;
         long  msRemaining  =  msTimeout ;

         while   (   (  value  !=  state  )   &&   (  msRemaining  >   0L   )   )   {
            wait ( msRemaining );
            msRemaining  =  endTime  -   System . currentTimeMillis ();
         }

         // May have timed out, or may have met value, 
         // calculate return value.
         return   (  value  ==  state  );
     }
}

source/chapter17/InterruptibleSyncBlock.java

source/chapter17/InterruptibleSyncBlock.java

public   class   InterruptibleSyncBlock   extends   Object   {
     private   Object  longLock ;
     private   BooleanLock  busyLock ;

     public   InterruptibleSyncBlock ()   {
        longLock  =   new   Object ();
        busyLock  =   new   BooleanLock ( false );
     }

     public   void  doStuff ()   throws   InterruptedException   {
        print ( "about to try to get exclusive access "   +
                 "to busyLock" );
        busyLock . waitToSetTrue ( 0 );

         try   {
            print ( "about to try to get exclusive access "   +
                     "to longLock" );
             synchronized   (  longLock  )   {
                print ( "got exclusive access to longLock" );
                 try   {  
                     Thread . sleep ( 10000 );  
                 }   catch   (   InterruptedException  x  )   {  
                     // ignore
                 }
                print ( "about to relinquish exclusive access "   +
                         "to longLock" );
             }
         }   finally   {
            print ( "about to free up busyLock" );
            busyLock . setValue ( false );
         }
     }

     private   static   void  print ( String  msg )   {
         String  name  =   Thread . currentThread (). getName ();
         System . err . println ( name  +   ": "   +  msg );
     }

     private   static   Thread  launch (
                 final   InterruptibleSyncBlock  sb ,  
                 String  name
             )   {

         Runnable  r  =   new   Runnable ()   {
                 public   void  run ()   {
                    print ( "in run()" );
                     try   {
                        sb . doStuff ();
                     }   catch   (   InterruptedException  x  )   {
                        print ( "InterruptedException thrown "   +
                                 "from doStuff()" );
                     }
                 }
             };
        
         Thread  t  =   new   Thread ( r ,  name );
        t . start ();

         return  t ;
     }

     public   static   void  main ( String []  args )   {
         try   {
             InterruptibleSyncBlock  sb  =  
                     new   InterruptibleSyncBlock ();
    
             Thread  t1  =  launch ( sb ,   "T1" );
             Thread . sleep ( 500 );

             Thread  t2  =  launch ( sb ,   "T2" );
             Thread  t3  =  launch ( sb ,   "T3" );

             Thread . sleep ( 1000 );

            print ( "about to interrupt T2" );
            t2 . interrupt ();
            print ( "just interrupted T2" );

         }   catch   (   InterruptedException  x  )   {
            x . printStackTrace ();
         }
     }
}

source/chapter17/Signaling.java

source/chapter17/Signaling.java

public   class   Signaling   extends   Object   {
     private   BooleanLock  readyLock ;

     public   Signaling ( BooleanLock  readyLock )   {
         this . readyLock  =  readyLock ;

         Runnable  r  =   new   Runnable ()   {
                 public   void  run ()   {
                     try   {
                        runWork ();
                     }   catch   (   Exception  x  )   {
                         // in case ANY exception slips through
                        x . printStackTrace ();  
                     }
                 }
             };

         Thread  internalThread  =   new   Thread ( r ,   "internal" );
        internalThread . start ();
     }
    
     private   void  runWork ()   {
         try   {
            print ( "about to wait for readyLock to be true" );
            readyLock . waitUntilTrue ( 0 );    // 0 - wait forever
            print ( "readyLock is now true" );
         }   catch   (   InterruptedException  x  )   {
            print ( "interrupted while waiting for readyLock "   +
                     "to become true" );
         }
     }

     private   static   void  print ( String  msg )   {
         String  name  =   Thread . currentThread (). getName ();
         System . err . println ( name  +   ": "   +  msg );
     }

     public   static   void  main ( String []  args )   {
         try   {
            print ( "creating BooleanLock instance" );
             BooleanLock  ready  =   new   BooleanLock ( false );
        
            print ( "creating Signaling instance" );
             new   Signaling ( ready );

            print ( "about to sleep for 3 seconds" );
             Thread . sleep ( 3000 );

            print ( "about to setValue to true" );
            ready . setValue ( true );
            print ( "ready.isTrue()="   +  ready . isTrue ());
         }   catch   (   InterruptedException  x  )   {
            x . printStackTrace ();
         }
     }
}

source/chapter17/SyncBlock.java

source/chapter17/SyncBlock.java

public   class   SyncBlock   extends   Object   {
     private   Object  longLock ;

     public   SyncBlock ()   {
        longLock  =   new   Object ();
     }

     public   void  doStuff ()   {
        print ( "about to try to get exclusive access "   +
                 "to longLock" );

         synchronized   (  longLock  )   {
            print ( "got exclusive access to longLock" );
             try   {   Thread . sleep ( 10000 );   }  
             catch   (   InterruptedException  x  )   {   }
            print ( "about to relinquish exclusive access to "   +
                     "longLock" );
         }
     }

     private   static   void  print ( String  msg )   {
         String  name  =   Thread . currentThread (). getName ();
         System . err . println ( name  +   ": "   +  msg );
     }

     private   static   Thread  launch (
                 final   SyncBlock  sb ,  
                 String  name
             )   {

         Runnable  r  =   new   Runnable ()   {
                 public   void  run ()   {
                    print ( "in run()" );
                    sb . doStuff ();
                 }
             };
        
         Thread  t  =   new   Thread ( r ,  name );
        t . start ();

         return  t ;
     }

     public   static   void  main ( String []  args )   {
         try   {
             SyncBlock  sb  =   new   SyncBlock ();
    
             Thread  t1  =  launch ( sb ,   "T1" );
             Thread . sleep ( 500 );

             Thread  t2  =  launch ( sb ,   "T2" );
             Thread  t3  =  launch ( sb ,   "T3" );

             Thread . sleep ( 1000 );

            print ( "about to interrupt T2" );
            t2 . interrupt ();
            print ( "just interrupted T2" );

         }   catch   (   InterruptedException  x  )   {
            x . printStackTrace ();
         }
     }
}

source/chapter17/TransitionDetector.java

source/chapter17/TransitionDetector.java

public   class   TransitionDetector   extends   Object   {
     private   boolean  value ;
     private   Object  valueLock ;
     private   Object  falseToTrueLock ;
     private   Object  trueToFalseLock ;

     public   TransitionDetector ( boolean  initialValue )   {
        value  =  initialValue ;
        valueLock  =   new   Object ();
        falseToTrueLock  =   new   Object ();
        trueToFalseLock  =   new   Object ();
     }

     public   void  setValue ( boolean  newValue )   {
         synchronized   (  valueLock  )   {
             if   (  newValue  !=  value  )   {
                value  =  newValue ;
                
                 if   (  value  )   {
                    notifyFalseToTrueWaiters ();
                 }   else   {
                    notifyTrueToFalseWaiters ();
                 }
             }
         }
     }

     public   void  pulseValue ()   {
         // Sync on valueLock to be sure that no other threads 
         // get into setValue() between these two setValue() 
         // calls.
         synchronized   (  valueLock  )   {
            setValue ( ! value );
            setValue ( ! value );
         }
     }

     public   boolean  isTrue ()   {
         synchronized   (  valueLock  )   {
             return  value ;
         }
     }

     public   void  waitForFalseToTrueTransition ()  
             throws   InterruptedException   {

         synchronized   (  falseToTrueLock  )   {
            falseToTrueLock . wait ();
         }
     }

     private   void  notifyFalseToTrueWaiters ()   {
         synchronized   (  falseToTrueLock  )   {
            falseToTrueLock . notifyAll ();
         }
     }

     public   void  waitForTrueToFalseTransition ()  
             throws   InterruptedException   {

         synchronized   (  trueToFalseLock  )   {
            trueToFalseLock . wait ();
         }
     }

     private   void  notifyTrueToFalseWaiters ()   {
         synchronized   (  trueToFalseLock  )   {
            trueToFalseLock . notifyAll ();
         }
     }

     public   String  toString ()   {
         return   String . valueOf ( isTrue ());
     }
}

source/chapter17/TransitionDetectorMain.java

source/chapter17/TransitionDetectorMain.java

public   class   TransitionDetectorMain   extends   Object   {
     private   static   Thread  startTrueWaiter (
                 final   TransitionDetector  td ,
                 String  name
             )   {

         Runnable  r  =   new   Runnable ()   {
                 public   void  run ()   {
                     try   {
                         while   (   true   )   {
                            print ( "about to wait for false-to-"   +
                                 "true transition, td="   +  td );

                            td . waitForFalseToTrueTransition ();

                            print ( "just noticed for false-to-"   +
                                 "true transition, td="   +  td );
                         }
                     }   catch   (   InterruptedException  ix  )   {
                         return ;
                     }
                 }
             };

         Thread  t  =   new   Thread ( r ,  name );
        t . start ();

         return  t ;
     }

     private   static   Thread  startFalseWaiter (
                 final   TransitionDetector  td ,
                 String  name
             )   {

         Runnable  r  =   new   Runnable ()   {
                 public   void  run ()   {
                     try   {
                         while   (   true   )   {
                            print ( "about to wait for true-to-"   +
                                 "false transition, td="   +  td );

                            td . waitForTrueToFalseTransition ();

                            print ( "just noticed for true-to-"   +
                                 "false transition, td="   +  td );
                         }
                     }   catch   (   InterruptedException  ix  )   {
                         return ;
                     }
                 }
             };

         Thread  t  =   new   Thread ( r ,  name );
        t . start ();

         return  t ;
     }

     private   static   void  print ( String  msg )   {
         String  name  =   Thread . currentThread (). getName ();
         System . err . println ( name  +   ": "   +  msg );
     }

     public   static   void  main ( String []  args )   {
         try   {
             TransitionDetector  td  =  
                     new   TransitionDetector ( false );

             Thread  threadA  =  startTrueWaiter ( td ,   "threadA" );
             Thread  threadB  =  startFalseWaiter ( td ,   "threadB" );

             Thread . sleep ( 200 );
            print ( "td="   +  td  +   ", about to set to 'false'" );
            td . setValue ( false );

             Thread . sleep ( 200 );
            print ( "td="   +  td  +   ", about to set to 'true'" );
            td . setValue ( true );

             Thread . sleep ( 200 );
            print ( "td="   +  td  +   ", about to pulse value" );
            td . pulseValue ();

             Thread . sleep ( 200 );
            threadA . interrupt ();
            threadB . interrupt ();
         }   catch   (   InterruptedException  x  )   {
            x . printStackTrace ();
         }
     }
}

source/chapter18/ByteFIFO.java

source/chapter18/ByteFIFO.java

public   class   ByteFIFO   extends   Object   {
     private   byte []  queue ;
     private   int  capacity ;
     private   int  size ;
     private   int  head ;
     private   int  tail ;

     public   ByteFIFO ( int  cap )   {
        capacity  =   (  cap  >   0   )   ?  cap  :   1 ;   // at least 1
        queue  =   new   byte [ capacity ];
        head  =   0 ;
        tail  =   0 ;
        size  =   0 ;
     }

     public   int  getCapacity ()   {
         return  capacity ;
     }

     public   synchronized   int  getSize ()   {
         return  size ;
     }

     public   synchronized   boolean  isEmpty ()   {
         return   (  size  ==   0   );
     }

     public   synchronized   boolean  isFull ()   {
         return   (  size  ==  capacity  );
     }

     public   synchronized   void  add ( byte  b )  
             throws   InterruptedException   {

        waitWhileFull ();

        queue [ head ]   =  b ;
        head  =   (  head  +   1   )   %  capacity ;
        size ++ ;

        notifyAll ();   // let any waiting threads know about change
     }

     public   synchronized   void  add ( byte []  list )  
             throws   InterruptedException   {

         // For efficiency, the bytes are copied in blocks
         // instead of one at a time. As space becomes available,
         // more bytes are copied until all of them have been
         // added.

         int  ptr  =   0 ;

         while   (  ptr  <  list . length  )   {
             // If full, the lock will be released to allow 
             // another thread to come in and remove bytes.
            waitWhileFull ();

             int  space  =  capacity  -  size ;
             int  distToEnd  =  capacity  -  head ;
             int  blockLen  =   Math . min ( space ,  distToEnd );

             int  bytesRemaining  =  list . length  -  ptr ;
             int  copyLen  =   Math . min ( blockLen ,  bytesRemaining );

             System . arraycopy ( list ,  ptr ,  queue ,  head ,  copyLen );
            head  =   (  head  +  copyLen  )   %  capacity ;
            size  +=  copyLen ;
            ptr  +=  copyLen ;

             // Keep the lock, but let any waiting threads 
             // know that something has changed.
            notifyAll ();
         }
     }

     public   synchronized   byte  remove ()  
             throws   InterruptedException   {

        waitWhileEmpty ();
        
         byte  b  =  queue [ tail ];
        tail  =   (  tail  +   1   )   %  capacity ;
        size -- ;

        notifyAll ();   // let any waiting threads know about change

         return  b ;
     }

     public   synchronized   byte []  removeAll ()   {
         // For efficiency, the bytes are copied in blocks
         // instead of one at a time. 

         if   (  isEmpty ()   )   {
             // Nothing to remove, return a zero-length
             // array and do not bother with notification
             // since nothing was removed.
             return   new   byte [ 0 ];  
         }

         // based on the current size
         byte []  list  =   new   byte [ size ];  

         // copy in the block from tail to the end
         int  distToEnd  =  capacity  -  tail ;
         int  copyLen  =   Math . min ( size ,  distToEnd );
         System . arraycopy ( queue ,  tail ,  list ,   0 ,  copyLen );

         // If data wraps around, copy the remaining data
         // from the front of the array.
         if   (  size  >  copyLen  )   {
             System . arraycopy (
                    queue ,   0 ,  list ,  copyLen ,  size  -  copyLen );
         }

        tail  =   (  tail  +  size  )   %  capacity ;
        size  =   0 ;   // everything has been removed

         // Signal any and all waiting threads that 
         // something has changed.
        notifyAll ();  

         return  list ;  
     }

     public   synchronized   byte []  removeAtLeastOne ()  
             throws   InterruptedException   {

        waitWhileEmpty ();   // wait for a least one to be in FIFO
         return  removeAll ();
     }

     public   synchronized   boolean  waitUntilEmpty ( long  msTimeout )  
             throws   InterruptedException   {

         if   (  msTimeout  ==   0L   )   {
            waitUntilEmpty ();    // use other method
             return   true ;
         }

         // wait only for the specified amount of time
         long  endTime  =   System . currentTimeMillis ()   +  msTimeout ;
         long  msRemaining  =  msTimeout ;

         while   (   ! isEmpty ()   &&   (  msRemaining  >   0L   )   )   {
            wait ( msRemaining );
            msRemaining  =  endTime  -   System . currentTimeMillis ();
         }

         // May have timed out, or may have met condition, 
         // calc return value.
         return  isEmpty ();
     }

     public   synchronized   void  waitUntilEmpty ()  
             throws   InterruptedException   {

         while   (   ! isEmpty ()   )   {
            wait ();
         }
     }

     public   synchronized   void  waitWhileEmpty ()  
             throws   InterruptedException   {

         while   (  isEmpty ()   )   {
            wait ();
         }
     }

     public   synchronized   void  waitUntilFull ()  
             throws   InterruptedException   {

         while   (   ! isFull ()   )   {
            wait ();
         }
     }

     public   synchronized   void  waitWhileFull ()  
             throws   InterruptedException   {

         while   (  isFull ()   )   {
            wait ();
         }
     }
}

source/chapter18/ByteFIFOTest.java

source/chapter18/ByteFIFOTest.java

import  java . io . * ;

public   class   ByteFIFOTest   extends   Object   {
     private   ByteFIFO  fifo ;
     private   byte []  srcData ;

     public   ByteFIFOTest ()   throws   IOException   {
        fifo  =   new   ByteFIFO ( 20 );

        makeSrcData ();
         System . out . println ( "srcData.length="   +  srcData . length );

         Runnable  srcRunnable  =   new   Runnable ()   {
                 public   void  run ()   {
                    src ();
                 }
             };
         Thread  srcThread  =   new   Thread ( srcRunnable );
        srcThread . start ();

         Runnable  dstRunnable  =   new   Runnable ()   {
                 public   void  run ()   {
                    dst ();
                 }
             };
         Thread  dstThread  =   new   Thread ( dstRunnable );
        dstThread . start ();
     }

     private   void  makeSrcData ()   throws   IOException   {
         String []  list  =   {
                 "The first string is right here" ,
                 "The second string is a bit longer and also right here" ,
                 "The third string" ,
                 "ABCDEFGHIJKLMNOPQRSTUVWXYZ" ,
                 "0123456789" ,
                 "The last string in the list"
             };

         ByteArrayOutputStream  baos  =   new   ByteArrayOutputStream ();
         ObjectOutputStream  oos  =   new   ObjectOutputStream ( baos );
        oos . writeObject ( list );
        oos . flush ();
        oos . close ();
        
        srcData  =  baos . toByteArray ();
     }

     private   void  src ()   {
         try   {
             boolean  justAddOne  =   true ;
             int  count  =   0 ;

             while   (  count  <  srcData . length  )   {
                 if   (   ! justAddOne  )   {
                     int  writeSize  =   ( int )   (   40.0   *   Math . random ()   );
                    writeSize  =   Math . min ( writeSize ,  srcData . length  -  count );

                     byte []  buf  =   new   byte [ writeSize ];
                     System . arraycopy ( srcData ,  count ,  buf ,   0 ,  writeSize );
                    fifo . add ( buf );
                    count  +=  writeSize ;

                     System . out . println ( "just added "   +  writeSize  +   " bytes" );
                 }   else   {
                    fifo . add ( srcData [ count ]);
                    count ++ ;

                     System . out . println ( "just added exactly 1 byte" );
                 }

                justAddOne  =   ! justAddOne ;
             }
         }   catch   (   InterruptedException  x  )   {
            x . printStackTrace ();
         }
     }

     private   void  dst ()   {
         try   {
             boolean  justAddOne  =   true ;
             int  count  =   0 ;
             byte []  dstData  =   new   byte [ srcData . length ];

             while   (  count  <  dstData . length  )   {
                 if   (   ! justAddOne  )   {
                     byte []  buf  =  fifo . removeAll ();
                     if   (  buf . length  >   0   )   {
                         System . arraycopy ( buf ,   0 ,  dstData ,  count ,  buf . length );
                        count  +=  buf . length ;
                     }

                     System . out . println (
                         "just removed "   +  buf . length  +   " bytes" );
                 }   else   {
                     byte  b  =  fifo . remove ();
                    dstData [ count ]   =  b ;
                    count ++ ;

                     System . out . println (
                         "just removed exactly 1 byte" );
                 }

                justAddOne  =   ! justAddOne ;
             }

             System . out . println ( "received all data, count="   +  count );

             ObjectInputStream  ois  =   new   ObjectInputStream (
                     new   ByteArrayInputStream ( dstData ));

             String []  line  =   ( String [])  ois . readObject ();

             for   (   int  i  =   0 ;  i  <  line . length ;  i ++   )   {
                 System . out . println ( "line["   +  i  +   "]="   +  line [ i ]);
             }
         }   catch   (   ClassNotFoundException  x1  )   {
            x1 . printStackTrace ();
         }   catch   (   IOException  iox  )   {
            iox . printStackTrace ();
         }   catch   (   InterruptedException  x  )   {
            x . printStackTrace ();
         }
     }

     public   static   void  main ( String []  args )   {
         try   {
             new   ByteFIFOTest ();
         }   catch   (   IOException  iox  )   {
            iox . printStackTrace ();
         }
     }
}

source/chapter18/ObjectFIFO.java

source/chapter18/ObjectFIFO.java

public   class   ObjectFIFO   extends   Object   {
     private   Object []  queue ;
     private   int  capacity ;
     private   int  size ;
     private   int  head ;
     private   int  tail ;

     public   ObjectFIFO ( int  cap )   {
        capacity  =   (  cap  >   0   )   ?  cap  :   1 ;   // at least 1
        queue  =   new   Object [ capacity ];
        head  =   0 ;
        tail  =   0 ;
        size  =   0 ;
     }

     public   int  getCapacity ()   {
         return  capacity ;
     }

     public   synchronized   int  getSize ()   {
         return  size ;
     }

     public   synchronized   boolean  isEmpty ()   {
         return   (  size  ==   0   );
     }

     public   synchronized   boolean  isFull ()   {
         return   (  size  ==  capacity  );
     }

     public   synchronized   void  add ( Object  obj )  
             throws   InterruptedException   {

        waitWhileFull ();

        queue [ head ]   =  obj ;
        head  =   (  head  +   1   )   %  capacity ;
        size ++ ;

        notifyAll ();   // let any waiting threads know about change
     }

     public   synchronized   void  addEach ( Object []  list )  
             throws   InterruptedException   {

         //
         // You might want to code a more efficient 
         // implementation here ... (see ByteFIFO.java)
         //

         for   (   int  i  =   0 ;  i  <  list . length ;  i ++   )   {
            add ( list [ i ]);
         }
     }

     public   synchronized   Object  remove ()  
             throws   InterruptedException   {

        waitWhileEmpty ();
        
         Object  obj  =  queue [ tail ];

         // don't block GC by keeping unnecessary reference
        queue [ tail ]   =   null ;  

        tail  =   (  tail  +   1   )   %  capacity ;
        size -- ;

        notifyAll ();   // let any waiting threads know about change

         return  obj ;
     }

     public   synchronized   Object []  removeAll ()  
             throws   InterruptedException   {

         //
         // You might want to code a more efficient 
         // implementation here ... (see ByteFIFO.java)
         //

         Object []  list  =   new   Object [ size ];   // use the current size

         for   (   int  i  =   0 ;  i  <  list . length ;  i ++   )   {
            list [ i ]   =  remove ();
         }

         // if FIFO was empty, a zero-length array is returned
         return  list ;  
     }

     public   synchronized   Object []  removeAtLeastOne ()  
             throws   InterruptedException   {

        waitWhileEmpty ();   // wait for a least one to be in FIFO
         return  removeAll ();
     }

     public   synchronized   boolean  waitUntilEmpty ( long  msTimeout )  
             throws   InterruptedException   {

         if   (  msTimeout  ==   0L   )   {
            waitUntilEmpty ();    // use other method
             return   true ;
         }

         // wait only for the specified amount of time
         long  endTime  =   System . currentTimeMillis ()   +  msTimeout ;
         long  msRemaining  =  msTimeout ;

         while   (   ! isEmpty ()   &&   (  msRemaining  >   0L   )   )   {
            wait ( msRemaining );
            msRemaining  =  endTime  -   System . currentTimeMillis ();
         }

         // May have timed out, or may have met condition, 
         // calc return value.
         return  isEmpty ();
     }

     public   synchronized   void  waitUntilEmpty ()  
             throws   InterruptedException   {

         while   (   ! isEmpty ()   )   {
            wait ();
         }
     }

     public   synchronized   void  waitWhileEmpty ()  
             throws   InterruptedException   {

         while   (  isEmpty ()   )   {
            wait ();
         }
     }

     public   synchronized   void  waitUntilFull ()  
             throws   InterruptedException   {

         while   (   ! isFull ()   )   {
            wait ();
         }
     }

     public   synchronized   void  waitWhileFull ()  
             throws   InterruptedException   {

         while   (  isFull ()   )   {
            wait ();
         }
     }
}

source/chapter18/ObjectFIFOTest.java

source/chapter18/ObjectFIFOTest.java

public   class   ObjectFIFOTest   extends   Object   {
    
     private   static   void  fullCheck ( ObjectFIFO  fifo )   {
         try   {
             // Sync'd to allow messages to print while 
             // condition is still true.
             synchronized   (  fifo  )   {
                 while   (   true   )   {
                    fifo . waitUntilFull ();
                    print ( "FULL" );
                    fifo . waitWhileFull ();
                    print ( "NO LONGER FULL" );
                 }
             }
         }   catch   (   InterruptedException  ix  )   {
             return ;
         }
     }

     private   static   void  emptyCheck ( ObjectFIFO  fifo )   {
         try   {
             // Sync'd to allow messages to print while 
             // condition is still true.
             synchronized   (  fifo  )   {
                 while   (   true   )   {
                    fifo . waitUntilEmpty ();
                    print ( "EMPTY" );
                    fifo . waitWhileEmpty ();
                    print ( "NO LONGER EMPTY" );
                 }
             }
         }   catch   (   InterruptedException  ix  )   {
             return ;
         }
     }

     private   static   void  consumer ( ObjectFIFO  fifo )   {
         try   {
            print ( "just entered consumer()" );

             for   (   int  i  =   0 ;  i  <   3 ;  i ++   )   {
                 synchronized   (  fifo  )   {
                     Object  obj  =  fifo . remove ();
                    print ( "DATA-OUT - did remove(), obj="   +  obj );
                 }
                 Thread . sleep ( 3000 );
             }

             synchronized   (  fifo  )   {
                 boolean  resultOfWait  =  fifo . waitUntilEmpty ( 500 );
                print ( "did waitUntilEmpty(500), resultOfWait="   +
                        resultOfWait  +   ", getSize()="   +  
                        fifo . getSize ());
             }

             for   (   int  i  =   0 ;  i  <   3 ;  i ++   )   {
                 synchronized   (  fifo  )   {
                     Object []  list  =  fifo . removeAll ();
                    print ( "did removeAll(), list.length="   +  
                            list . length );

                     for   (   int  j  =   0 ;  j  <  list . length ;  j ++   )   {
                        print ( "DATA-OUT - list["   +  j  +   "]="   +  
                                list [ j ]);
                     }
                 }
                 Thread . sleep ( 100 );
             }

             for   (   int  i  =   0 ;  i  <   3 ;  i ++   )   {
                 synchronized   (  fifo  )   {
                     Object []  list  =  fifo . removeAtLeastOne ();
                    print (
                         "did removeAtLeastOne(), list.length="   +
                        list . length );

                     for   (   int  j  =   0 ;  j  <  list . length ;  j ++   )   {
                        print ( "DATA-OUT - list["   +  j  +   "]="   +  
                                list [ j ]);
                     }
                 }
                 Thread . sleep ( 1000 );
             }

             while   (   ! fifo . isEmpty ()   )   {
                 synchronized   (  fifo  )   {
                     Object  obj  =  fifo . remove ();
                    print ( "DATA-OUT - did remove(), obj="   +  obj );
                 }
                 Thread . sleep ( 1000 );
             }

            print ( "leaving consumer()" );
         }   catch   (   InterruptedException  ix  )   {
             return ;
         }
     }

     private   static   void  producer ( ObjectFIFO  fifo )   {
         try   {
            print ( "just entered producer()" );
             int  count  =   0 ;

             Object  obj0  =   new   Integer ( count );
            count ++ ;
             synchronized   (  fifo  )   {
                fifo . add ( obj0 );
                print ( "DATA-IN - did add(), obj0="   +  obj0 );

                 boolean  resultOfWait  =  fifo . waitUntilEmpty ( 500 );
                print ( "did waitUntilEmpty(500), resultOfWait="   +
                        resultOfWait  +   ", getSize()="   +  
                        fifo . getSize ());
             }

             for   (   int  i  =   0 ;  i  <   10 ;  i ++   )   {
                 Object  obj  =   new   Integer ( count );
                count ++ ;
                 synchronized   (  fifo  )   {
                    fifo . add ( obj );
                    print ( "DATA-IN - did add(), obj="   +  obj );
                 }
                 Thread . sleep ( 1000 );
             }

             Thread . sleep ( 2000 );

             Object  obj  =   new   Integer ( count );
            count ++ ;
             synchronized   (  fifo  )   {
                fifo . add ( obj );
                print ( "DATA-IN - did add(), obj="   +  obj );
             }
             Thread . sleep ( 500 );

             Integer []  list1  =   new   Integer [ 3 ];
             for   (   int  i  =   0 ;  i  <  list1 . length ;  i ++   )   {
                list1 [ i ]   =   new   Integer ( count );
                count ++ ;
             }

             synchronized   (  fifo  )   {
                fifo . addEach ( list1 );
                print ( "did addEach(), list1.length="   +  
                        list1 . length );
             }

             Integer []  list2  =   new   Integer [ 8 ];
             for   (   int  i  =   0 ;  i  <  list2 . length ;  i ++   )   {
                list2 [ i ]   =   new   Integer ( count );
                count ++ ;
             }

             synchronized   (  fifo  )   {
                fifo . addEach ( list2 );
                print ( "did addEach(), list2.length="   +  
                        list2 . length );
             }

             synchronized   (  fifo  )   {
                fifo . waitUntilEmpty ();
                print ( "fifo.isEmpty()="   +  fifo . isEmpty ());
             }

            print ( "leaving producer()" );
         }   catch   (   InterruptedException  ix  )   {
             return ;
         }
     }

     private   static   synchronized   void  print ( String  msg )   {
         System . out . println (
             Thread . currentThread (). getName ()   +   ": "   +  msg );
     }

     public   static   void  main ( String []  args )   {
         final   ObjectFIFO  fifo  =   new   ObjectFIFO ( 5 );

         Runnable  fullCheckRunnable  =   new   Runnable ()   {
                 public   void  run ()   {
                    fullCheck ( fifo );
                 }
             };

         Thread  fullCheckThread  =  
                 new   Thread ( fullCheckRunnable ,   "fchk" );
        fullCheckThread . setPriority ( 9 );
        fullCheckThread . setDaemon ( true );   // die automatically
        fullCheckThread . start ();

         Runnable  emptyCheckRunnable  =   new   Runnable ()   {
                 public   void  run ()   {
                    emptyCheck ( fifo );
                 }
             };

         Thread  emptyCheckThread  =  
                 new   Thread ( emptyCheckRunnable ,   "echk" );
        emptyCheckThread . setPriority ( 8 );
        emptyCheckThread . setDaemon ( true );   // die automatically
        emptyCheckThread . start ();

         Runnable  consumerRunnable  =   new   Runnable ()   {
                 public   void  run ()   {
                    consumer ( fifo );
                 }
             };

         Thread  consumerThread  =  
                 new   Thread ( consumerRunnable ,   "cons" );
        consumerThread . setPriority ( 7 );
        consumerThread . start ();

         Runnable  producerRunnable  =   new   Runnable ()   {
                 public   void  run ()   {
                    producer ( fifo );
                 }
             };

         Thread  producerThread  =  
                 new   Thread ( producerRunnable ,   "prod" );
        producerThread . setPriority ( 6 );
        producerThread . start ();
     }
}

source/chapter18/SimpleObjectFIFO.java

source/chapter18/SimpleObjectFIFO.java

public   class   SimpleObjectFIFO   extends   Object   {
     private   Object []  queue ;
     private   int  capacity ;
     private   int  size ;
     private   int  head ;
     private   int  tail ;

     public   SimpleObjectFIFO ( int  cap )   {
        capacity  =   (  cap  >   0   )   ?  cap  :   1 ;   // at least 1
        queue  =   new   Object [ capacity ];
        head  =   0 ;
        tail  =   0 ;
        size  =   0 ;
     }

     public   synchronized   int  getSize ()   {
         return  size ;
     }

     public   synchronized   boolean  isFull ()   {
         return   (  size  ==  capacity  );
     }

     public   synchronized   void  add ( Object  obj )   throws   InterruptedException   {
         while   (  isFull ()   )   {
            wait ();
         }

        queue [ head ]   =  obj ;
        head  =   (  head  +   1   )   %  capacity ;
        size ++ ;

        notifyAll ();   // let any waiting threads know about change
     }

     public   synchronized   Object  remove ()   throws   InterruptedException   {
         while   (  size  ==   0   )   {
            wait ();
         }
        
         Object  obj  =  queue [ tail ];
        queue [ tail ]   =   null ;   // don't block GC by keeping unnecessary reference
        tail  =   (  tail  +   1   )   %  capacity ;
        size -- ;

        notifyAll ();   // let any waiting threads know about change

         return  obj ;
     }

     public   synchronized   void  printState ()   {
         StringBuffer  sb  =   new   StringBuffer ();

        sb . append ( "SimpleObjectFIFO:\n" );
        sb . append ( "       capacity="   +  capacity  +   "\n" );

        sb . append ( "           size="   +  size );
         if   (  isFull ()   )   {
            sb . append ( " - FULL" );
         }   else   if   (  size  ==   0   )   {
            sb . append ( " - EMPTY" );
         }
        sb . append ( "\n" );

        sb . append ( "           head="   +  head  +   "\n" );
        sb . append ( "           tail="   +  tail  +   "\n" );

         for   (   int  i  =   0 ;  i  <  queue . length ;  i ++   )   {
            sb . append ( "       queue["   +  i  +   "]="   +  queue [ i ]   +   "\n" );
         }

         System . out . print ( sb );
     }
}

source/chapter18/SimpleObjectFIFOTest.java

source/chapter18/SimpleObjectFIFOTest.java

public   class   SimpleObjectFIFOTest   extends   Object   {
     public   static   void  main ( String []  args )   {
         try   {
             SimpleObjectFIFO  fifo  =   new   SimpleObjectFIFO ( 5 );
            fifo . printState ();
    
            fifo . add ( "S01" );
            fifo . printState ();
    
            fifo . add ( "S02" );
            fifo . printState ();
    
            fifo . add ( "S03" );
            fifo . printState ();
    
             Object  obj  =  fifo . remove ();
             System . out . println ( "just removed obj="   +  obj );
            fifo . printState ();
    
            fifo . add ( "S04" );
            fifo . printState ();
    
            fifo . add ( "S05" );
            fifo . printState ();
    
            fifo . add ( "S06" );
            fifo . printState ();
         }   catch   (   InterruptedException  x  )   {
            x . printStackTrace ();
         }
     }
}
root
source.tar.Z
Page 2: Java Thread Programming -- SAMS
Page 3: Java Thread Programming -- SAMS
Page 4: Java Thread Programming -- SAMS
Page 5: Java Thread Programming -- SAMS
Page 6: Java Thread Programming -- SAMS
Page 7: Java Thread Programming -- SAMS
Page 8: Java Thread Programming -- SAMS
Page 9: Java Thread Programming -- SAMS
Page 10: Java Thread Programming -- SAMS
Page 11: Java Thread Programming -- SAMS
Page 12: Java Thread Programming -- SAMS
Page 13: Java Thread Programming -- SAMS
Page 14: Java Thread Programming -- SAMS
Page 15: Java Thread Programming -- SAMS
Page 16: Java Thread Programming -- SAMS
Page 17: Java Thread Programming -- SAMS
Page 18: Java Thread Programming -- SAMS
Page 19: Java Thread Programming -- SAMS
Page 20: Java Thread Programming -- SAMS
Page 21: Java Thread Programming -- SAMS
Page 22: Java Thread Programming -- SAMS
Page 23: Java Thread Programming -- SAMS
Page 24: Java Thread Programming -- SAMS
Page 25: Java Thread Programming -- SAMS
Page 26: Java Thread Programming -- SAMS
Page 27: Java Thread Programming -- SAMS
Page 28: Java Thread Programming -- SAMS
Page 29: Java Thread Programming -- SAMS
Page 30: Java Thread Programming -- SAMS
Page 31: Java Thread Programming -- SAMS
Page 32: Java Thread Programming -- SAMS
Page 33: Java Thread Programming -- SAMS
Page 34: Java Thread Programming -- SAMS
Page 35: Java Thread Programming -- SAMS
Page 36: Java Thread Programming -- SAMS
Page 37: Java Thread Programming -- SAMS
Page 38: Java Thread Programming -- SAMS
Page 39: Java Thread Programming -- SAMS
Page 40: Java Thread Programming -- SAMS
Page 41: Java Thread Programming -- SAMS
Page 42: Java Thread Programming -- SAMS
Page 43: Java Thread Programming -- SAMS
Page 44: Java Thread Programming -- SAMS
Page 45: Java Thread Programming -- SAMS
Page 46: Java Thread Programming -- SAMS
Page 47: Java Thread Programming -- SAMS
Page 48: Java Thread Programming -- SAMS
Page 49: Java Thread Programming -- SAMS
Page 50: Java Thread Programming -- SAMS
Page 51: Java Thread Programming -- SAMS
Page 52: Java Thread Programming -- SAMS
Page 53: Java Thread Programming -- SAMS
Page 54: Java Thread Programming -- SAMS
Page 55: Java Thread Programming -- SAMS
Page 56: Java Thread Programming -- SAMS
Page 57: Java Thread Programming -- SAMS
Page 58: Java Thread Programming -- SAMS
Page 59: Java Thread Programming -- SAMS
Page 60: Java Thread Programming -- SAMS
Page 61: Java Thread Programming -- SAMS
Page 62: Java Thread Programming -- SAMS
Page 63: Java Thread Programming -- SAMS
Page 64: Java Thread Programming -- SAMS
Page 65: Java Thread Programming -- SAMS
Page 66: Java Thread Programming -- SAMS
Page 67: Java Thread Programming -- SAMS
Page 68: Java Thread Programming -- SAMS
Page 69: Java Thread Programming -- SAMS
Page 70: Java Thread Programming -- SAMS
Page 71: Java Thread Programming -- SAMS
Page 72: Java Thread Programming -- SAMS
Page 73: Java Thread Programming -- SAMS
Page 74: Java Thread Programming -- SAMS
Page 75: Java Thread Programming -- SAMS
Page 76: Java Thread Programming -- SAMS
Page 77: Java Thread Programming -- SAMS
Page 78: Java Thread Programming -- SAMS
Page 79: Java Thread Programming -- SAMS
Page 80: Java Thread Programming -- SAMS
Page 81: Java Thread Programming -- SAMS
Page 82: Java Thread Programming -- SAMS
Page 83: Java Thread Programming -- SAMS
Page 84: Java Thread Programming -- SAMS
Page 85: Java Thread Programming -- SAMS
Page 86: Java Thread Programming -- SAMS
Page 87: Java Thread Programming -- SAMS
Page 88: Java Thread Programming -- SAMS
Page 89: Java Thread Programming -- SAMS
Page 90: Java Thread Programming -- SAMS
Page 91: Java Thread Programming -- SAMS
Page 92: Java Thread Programming -- SAMS
Page 93: Java Thread Programming -- SAMS
Page 94: Java Thread Programming -- SAMS
Page 95: Java Thread Programming -- SAMS
Page 96: Java Thread Programming -- SAMS
Page 97: Java Thread Programming -- SAMS
Page 98: Java Thread Programming -- SAMS
Page 99: Java Thread Programming -- SAMS
Page 100: Java Thread Programming -- SAMS
Page 101: Java Thread Programming -- SAMS
Page 102: Java Thread Programming -- SAMS
Page 103: Java Thread Programming -- SAMS
Page 104: Java Thread Programming -- SAMS
Page 105: Java Thread Programming -- SAMS
Page 106: Java Thread Programming -- SAMS
Page 107: Java Thread Programming -- SAMS
Page 108: Java Thread Programming -- SAMS
Page 109: Java Thread Programming -- SAMS
Page 110: Java Thread Programming -- SAMS
Page 111: Java Thread Programming -- SAMS
Page 112: Java Thread Programming -- SAMS
Page 113: Java Thread Programming -- SAMS
Page 114: Java Thread Programming -- SAMS
Page 115: Java Thread Programming -- SAMS
Page 116: Java Thread Programming -- SAMS
Page 117: Java Thread Programming -- SAMS
Page 118: Java Thread Programming -- SAMS
Page 119: Java Thread Programming -- SAMS
Page 120: Java Thread Programming -- SAMS
Page 121: Java Thread Programming -- SAMS
Page 122: Java Thread Programming -- SAMS
Page 123: Java Thread Programming -- SAMS
Page 124: Java Thread Programming -- SAMS
Page 125: Java Thread Programming -- SAMS
Page 126: Java Thread Programming -- SAMS
Page 127: Java Thread Programming -- SAMS
Page 128: Java Thread Programming -- SAMS
Page 129: Java Thread Programming -- SAMS
Page 130: Java Thread Programming -- SAMS
Page 131: Java Thread Programming -- SAMS
Page 132: Java Thread Programming -- SAMS
Page 133: Java Thread Programming -- SAMS
Page 134: Java Thread Programming -- SAMS
Page 135: Java Thread Programming -- SAMS
Page 136: Java Thread Programming -- SAMS
Page 137: Java Thread Programming -- SAMS
Page 138: Java Thread Programming -- SAMS
Page 139: Java Thread Programming -- SAMS
Page 140: Java Thread Programming -- SAMS
Page 141: Java Thread Programming -- SAMS
Page 142: Java Thread Programming -- SAMS
Page 143: Java Thread Programming -- SAMS
Page 144: Java Thread Programming -- SAMS
Page 145: Java Thread Programming -- SAMS
Page 146: Java Thread Programming -- SAMS
Page 147: Java Thread Programming -- SAMS
Page 148: Java Thread Programming -- SAMS
Page 149: Java Thread Programming -- SAMS
Page 150: Java Thread Programming -- SAMS
Page 151: Java Thread Programming -- SAMS
Page 152: Java Thread Programming -- SAMS
Page 153: Java Thread Programming -- SAMS
Page 154: Java Thread Programming -- SAMS
Page 155: Java Thread Programming -- SAMS
Page 156: Java Thread Programming -- SAMS
Page 157: Java Thread Programming -- SAMS
Page 158: Java Thread Programming -- SAMS
Page 159: Java Thread Programming -- SAMS
Page 160: Java Thread Programming -- SAMS
Page 161: Java Thread Programming -- SAMS
Page 162: Java Thread Programming -- SAMS
Page 163: Java Thread Programming -- SAMS
Page 164: Java Thread Programming -- SAMS
Page 165: Java Thread Programming -- SAMS
Page 166: Java Thread Programming -- SAMS
Page 167: Java Thread Programming -- SAMS
Page 168: Java Thread Programming -- SAMS
Page 169: Java Thread Programming -- SAMS
Page 170: Java Thread Programming -- SAMS
Page 171: Java Thread Programming -- SAMS
Page 172: Java Thread Programming -- SAMS
Page 173: Java Thread Programming -- SAMS
Page 174: Java Thread Programming -- SAMS
Page 175: Java Thread Programming -- SAMS
Page 176: Java Thread Programming -- SAMS
Page 177: Java Thread Programming -- SAMS
Page 178: Java Thread Programming -- SAMS
Page 179: Java Thread Programming -- SAMS
Page 180: Java Thread Programming -- SAMS
Page 181: Java Thread Programming -- SAMS
Page 182: Java Thread Programming -- SAMS
Page 183: Java Thread Programming -- SAMS
Page 184: Java Thread Programming -- SAMS
Page 185: Java Thread Programming -- SAMS
Page 186: Java Thread Programming -- SAMS
Page 187: Java Thread Programming -- SAMS
Page 188: Java Thread Programming -- SAMS
Page 189: Java Thread Programming -- SAMS
Page 190: Java Thread Programming -- SAMS
Page 191: Java Thread Programming -- SAMS
Page 192: Java Thread Programming -- SAMS
Page 193: Java Thread Programming -- SAMS
Page 194: Java Thread Programming -- SAMS
Page 195: Java Thread Programming -- SAMS
Page 196: Java Thread Programming -- SAMS
Page 197: Java Thread Programming -- SAMS
Page 198: Java Thread Programming -- SAMS
Page 199: Java Thread Programming -- SAMS
Page 200: Java Thread Programming -- SAMS
Page 201: Java Thread Programming -- SAMS
Page 202: Java Thread Programming -- SAMS
Page 203: Java Thread Programming -- SAMS
Page 204: Java Thread Programming -- SAMS
Page 205: Java Thread Programming -- SAMS
Page 206: Java Thread Programming -- SAMS
Page 207: Java Thread Programming -- SAMS
Page 208: Java Thread Programming -- SAMS
Page 209: Java Thread Programming -- SAMS
Page 210: Java Thread Programming -- SAMS
Page 211: Java Thread Programming -- SAMS
Page 212: Java Thread Programming -- SAMS
Page 213: Java Thread Programming -- SAMS
Page 214: Java Thread Programming -- SAMS
Page 215: Java Thread Programming -- SAMS
Page 216: Java Thread Programming -- SAMS
Page 217: Java Thread Programming -- SAMS
Page 218: Java Thread Programming -- SAMS
Page 219: Java Thread Programming -- SAMS
Page 220: Java Thread Programming -- SAMS
Page 221: Java Thread Programming -- SAMS
Page 222: Java Thread Programming -- SAMS
Page 223: Java Thread Programming -- SAMS
Page 224: Java Thread Programming -- SAMS
Page 225: Java Thread Programming -- SAMS
Page 226: Java Thread Programming -- SAMS
Page 227: Java Thread Programming -- SAMS
Page 228: Java Thread Programming -- SAMS
Page 229: Java Thread Programming -- SAMS
Page 230: Java Thread Programming -- SAMS
Page 231: Java Thread Programming -- SAMS
Page 232: Java Thread Programming -- SAMS
Page 233: Java Thread Programming -- SAMS
Page 234: Java Thread Programming -- SAMS
Page 235: Java Thread Programming -- SAMS
Page 236: Java Thread Programming -- SAMS
Page 237: Java Thread Programming -- SAMS
Page 238: Java Thread Programming -- SAMS
Page 239: Java Thread Programming -- SAMS
Page 240: Java Thread Programming -- SAMS
Page 241: Java Thread Programming -- SAMS
Page 242: Java Thread Programming -- SAMS
Page 243: Java Thread Programming -- SAMS
Page 244: Java Thread Programming -- SAMS
Page 245: Java Thread Programming -- SAMS
Page 246: Java Thread Programming -- SAMS
Page 247: Java Thread Programming -- SAMS
Page 248: Java Thread Programming -- SAMS
Page 249: Java Thread Programming -- SAMS
Page 250: Java Thread Programming -- SAMS
Page 251: Java Thread Programming -- SAMS
Page 252: Java Thread Programming -- SAMS
Page 253: Java Thread Programming -- SAMS
Page 254: Java Thread Programming -- SAMS
Page 255: Java Thread Programming -- SAMS
Page 256: Java Thread Programming -- SAMS
Page 257: Java Thread Programming -- SAMS
Page 258: Java Thread Programming -- SAMS
Page 259: Java Thread Programming -- SAMS
Page 260: Java Thread Programming -- SAMS
Page 261: Java Thread Programming -- SAMS
Page 262: Java Thread Programming -- SAMS
Page 263: Java Thread Programming -- SAMS
Page 264: Java Thread Programming -- SAMS
Page 265: Java Thread Programming -- SAMS
Page 266: Java Thread Programming -- SAMS
Page 267: Java Thread Programming -- SAMS
Page 268: Java Thread Programming -- SAMS
Page 269: Java Thread Programming -- SAMS
Page 270: Java Thread Programming -- SAMS
Page 271: Java Thread Programming -- SAMS
Page 272: Java Thread Programming -- SAMS
Page 273: Java Thread Programming -- SAMS
Page 274: Java Thread Programming -- SAMS
Page 275: Java Thread Programming -- SAMS
Page 276: Java Thread Programming -- SAMS
Page 277: Java Thread Programming -- SAMS
Page 278: Java Thread Programming -- SAMS
Page 279: Java Thread Programming -- SAMS
Page 280: Java Thread Programming -- SAMS
Page 281: Java Thread Programming -- SAMS
Page 282: Java Thread Programming -- SAMS
Page 283: Java Thread Programming -- SAMS
Page 284: Java Thread Programming -- SAMS
Page 285: Java Thread Programming -- SAMS
Page 286: Java Thread Programming -- SAMS
Page 287: Java Thread Programming -- SAMS
Page 288: Java Thread Programming -- SAMS
Page 289: Java Thread Programming -- SAMS
Page 290: Java Thread Programming -- SAMS
Page 291: Java Thread Programming -- SAMS
Page 292: Java Thread Programming -- SAMS
Page 293: Java Thread Programming -- SAMS
Page 294: Java Thread Programming -- SAMS
Page 295: Java Thread Programming -- SAMS
Page 296: Java Thread Programming -- SAMS
Page 297: Java Thread Programming -- SAMS
Page 298: Java Thread Programming -- SAMS
Page 299: Java Thread Programming -- SAMS
Page 300: Java Thread Programming -- SAMS
Page 301: Java Thread Programming -- SAMS
Page 302: Java Thread Programming -- SAMS
Page 303: Java Thread Programming -- SAMS
Page 304: Java Thread Programming -- SAMS
Page 305: Java Thread Programming -- SAMS
Page 306: Java Thread Programming -- SAMS
Page 307: Java Thread Programming -- SAMS
Page 308: Java Thread Programming -- SAMS
Page 309: Java Thread Programming -- SAMS
Page 310: Java Thread Programming -- SAMS
Page 311: Java Thread Programming -- SAMS
Page 312: Java Thread Programming -- SAMS
Page 313: Java Thread Programming -- SAMS
Page 314: Java Thread Programming -- SAMS
Page 315: Java Thread Programming -- SAMS
Page 316: Java Thread Programming -- SAMS
Page 317: Java Thread Programming -- SAMS
Page 318: Java Thread Programming -- SAMS
Page 319: Java Thread Programming -- SAMS
Page 320: Java Thread Programming -- SAMS
Page 321: Java Thread Programming -- SAMS
Page 322: Java Thread Programming -- SAMS
Page 323: Java Thread Programming -- SAMS
Page 324: Java Thread Programming -- SAMS
Page 325: Java Thread Programming -- SAMS
Page 326: Java Thread Programming -- SAMS
Page 327: Java Thread Programming -- SAMS
Page 328: Java Thread Programming -- SAMS
Page 329: Java Thread Programming -- SAMS
Page 330: Java Thread Programming -- SAMS
Page 331: Java Thread Programming -- SAMS
Page 332: Java Thread Programming -- SAMS
Page 333: Java Thread Programming -- SAMS
Page 334: Java Thread Programming -- SAMS
Page 335: Java Thread Programming -- SAMS
Page 336: Java Thread Programming -- SAMS
Page 337: Java Thread Programming -- SAMS
Page 338: Java Thread Programming -- SAMS
Page 339: Java Thread Programming -- SAMS
Page 340: Java Thread Programming -- SAMS
Page 341: Java Thread Programming -- SAMS
Page 342: Java Thread Programming -- SAMS
Page 343: Java Thread Programming -- SAMS
Page 344: Java Thread Programming -- SAMS
Page 345: Java Thread Programming -- SAMS
Page 346: Java Thread Programming -- SAMS
Page 347: Java Thread Programming -- SAMS
Page 348: Java Thread Programming -- SAMS
Page 349: Java Thread Programming -- SAMS
Page 350: Java Thread Programming -- SAMS
Page 351: Java Thread Programming -- SAMS
Page 352: Java Thread Programming -- SAMS
Page 353: Java Thread Programming -- SAMS
Page 354: Java Thread Programming -- SAMS
Page 355: Java Thread Programming -- SAMS
Page 356: Java Thread Programming -- SAMS
Page 357: Java Thread Programming -- SAMS
Page 358: Java Thread Programming -- SAMS
Page 359: Java Thread Programming -- SAMS
Page 360: Java Thread Programming -- SAMS
Page 361: Java Thread Programming -- SAMS
Page 362: Java Thread Programming -- SAMS
Page 363: Java Thread Programming -- SAMS
Page 364: Java Thread Programming -- SAMS
Page 365: Java Thread Programming -- SAMS
Page 366: Java Thread Programming -- SAMS
Page 367: Java Thread Programming -- SAMS
Page 368: Java Thread Programming -- SAMS
Page 369: Java Thread Programming -- SAMS
Page 370: Java Thread Programming -- SAMS
Page 371: Java Thread Programming -- SAMS
Page 372: Java Thread Programming -- SAMS
Page 373: Java Thread Programming -- SAMS
Page 374: Java Thread Programming -- SAMS
Page 375: Java Thread Programming -- SAMS