| 
 | ||||
| Copyright 1999 Sams Publishing | 
|  | ||
 
 |   | |
| Using BufferedThreadedInputStream for Interruptible I/O | 
|   | |
| Now its time to combine the techniques presented so far. CalcServerTwo (see Listing 15.9) has been slightly modified to work with CalcWorkerTwo . CalcWorkerTwo (see Listing 15.10 ) now uses a BufferedThreadedInputStream as an inline filter so that when it is blocked trying to read() , it will respond to an interrupt. | 
|   | |
| Listing 15.9 CalcServerTwo.javaModified to Work with CalcWorkerTwo | 
|   | |
| 1: import java.io.*; | 
| 2: import java.net.*; | 
| 3: import java.util.*; | 
| 4: | 
| 5: public class CalcServerTwo extends Object { | 
| 6: private ServerSocket ss; | 
| 7: private List workerList; | 
| 8: | 
| 9: private Thread internalThread; | 
| 10: private volatile boolean noStopRequested; | 
| 11: | 
| 12: public CalcServerTwo (int port) throws IOException { | 
| 13: ss = new ServerSocket(port); | 
| 14: workerList = new LinkedList(); | 
| 15: | 
| 16: noStopRequested = true; | 
| 17: Runnable r = new Runnable() { | 
| 18: public void run() { | 
| 19: try { | 
| 20: runWork(); | 
| 21: } catch (Exception x) { | 
| 22: // in case ANY exception slips through | 
| 23: x.printStackTrace(); | 
| 24: } | 
| 25: } | 
| 26: }; | 
| 27: | 
| 28: internalThread = new Thread(r); | 
| 29: internalThread.start(); | 
| 30: } | 
| 31: | 
| 32: private void runWork() { | 
| 33: System.out.println( | 
| 34: in CalcServer - ready to accept connections); | 
| 35: | 
| 36: while (noStopRequested) { | 
| 37: try { | 
| 38: System.out.println( | 
| 39: in CalcServer - about to block + | 
| 40: waiting for a new connection); | 
| 41: Socket sock = ss.accept(); | 
| 42: System.out.println( | 
| 43: in CalcServer - received new connection); | 
| 44: workerList.add(new CalcWorkerTwo (sock)); | 
| 45: } catch (IOException iox) { | 
| 46: if (noStopRequested) { | 
| 47: iox.printStackTrace(); | 
| 48: } | 
| 49: } | 
| 50: } | 
| 51: | 
| 52: // stop all the workers that were created | 
| 53: System.out.println(in CalcServer - putting in a + | 
| 54: stop request to all the workers); | 
| 55: Iterator iter = workerList.iterator(); | 
| 56: while (iter.hasNext()) { | 
| 57: CalcWorkerTwo worker = ( CalcWorkerTwo ) iter. next (); | 
| 58: worker.stopRequest(); | 
| 59: } | 
| 60: | 
| 61: System.out.println(in CalcServer - leaving runWork()); | 
| 62: } | 
| 63: | 
| 64: public void stopRequest() { | 
| 65: System.out.println( | 
| 66: in CalcServer - entering stopRequest()); | 
| 67: noStopRequested = false; | 
| 68: internalThread.interrupt(); | 
| 69: | 
| 70: if (ss != null) { | 
| 71: try { | 
| 72: ss.close(); | 
| 73: } catch (IOException x) { | 
| 74: // ignore | 
| 75: } finally { | 
| 76: ss = null; | 
| 77: } | 
| 78: } | 
| 79: } | 
| 80: | 
| 81: public boolean isAlive() { | 
| 82: return internalThread.isAlive(); | 
| 83: } | 
| 84: | 
| 85: public static void main(String[] args) { | 
| 86: int port = 2001; | 
| 87: | 
| 88: try { | 
| 89: CalcServerTwo server = new CalcServerTwo (port); | 
| 90: Thread.sleep(15000); | 
| 91: server.stopRequest(); | 
| 92: } catch (IOException x) { | 
| 93: x.printStackTrace(); | 
| 94: } catch (InterruptedException x) { | 
| 95: // ignore | 
| 96: } | 
| 97: } | 
| 98: } | 
|   | |
| Listing 15.10 CalcWorkerTwo.javaUsing BufferedThreadedInputStream | 
|   | |
| 1: import java.io.*; | 
| 2: import java.net.*; | 
| 3: | 
| 4: public class CalcWorkerTwo extends Object { | 
| 5: private DataInputStream dataIn; | 
| 6: private DataOutputStream dataOut; | 
| 7: | 
| 8: private Thread internalThread; | 
| 9: private volatile boolean noStopRequested; | 
| 10: | 
| 11: public CalcWorkerTwo(Socket sock) throws IOException { | 
| 12: dataIn = new DataInputStream( | 
| 13: new BufferedThreadedInputStream( | 
| 14: sock.getInputStream())); | 
| 15: dataOut = new DataOutputStream( | 
| 16: new BufferedOutputStream( | 
| 17: sock.getOutputStream())); | 
| 18: | 
| 19: noStopRequested = true; | 
| 20: Runnable r = new Runnable() { | 
| 21: public void run() { | 
| 22: try { | 
| 23: runWork(); | 
| 24: } catch (Exception x) { | 
| 25: // in case ANY exception slips through | 
| 26: x.printStackTrace(); | 
| 27: } | 
| 28: } | 
| 29: }; | 
| 30: | 
| 31: internalThread = new Thread(r); | 
| 32: internalThread.start(); | 
| 33: } | 
| 34: | 
| 35: private void runWork() { | 
| 36: while (noStopRequested) { | 
| 37: try { | 
| 38: System.out.println(in CalcWorker - about to + | 
| 39: block waiting to read a double); | 
| 40: double val = dataIn.readDouble(); | 
| 41: System.out.println( | 
| 42: in CalcWorker - read a double!); | 
| 43: dataOut.writeDouble(Math.sqrt(val)); | 
| 44: dataOut.flush(); | 
| 45: } catch (InterruptedIOException iiox) { | 
| 46: System.out.println(in CalcWorker - blocked + | 
| 47: read was interrupted !!!); | 
| 48: } catch (IOException x) { | 
| 49: if (noStopRequested) { | 
| 50: x.printStackTrace(); | 
| 51: stopRequest(); | 
| 52: } | 
| 53: } | 
| 54: } | 
| 55: | 
| 56: // In real-world code, be sure to close other streams | 
| 57: // and the socket as part of the clean-up. Omitted here | 
| 58: // for brevity. | 
| 59: | 
| 60: System.out.println(in CalcWorker - leaving runWork()); | 
| 61: } | 
| 62: | 
| 63: public void stopRequest() { | 
| 64: System.out.println( | 
| 65: in CalcWorker - entering stopRequest()); | 
| 66: noStopRequested = false; | 
| 67: internalThread.interrupt(); | 
| 68: System.out.println( | 
| 69: in CalcWorker - leaving stopRequest()); | 
| 70: } | 
| 71: | 
| 72: public boolean isAlive() { | 
| 73: return internalThread.isAlive(); | 
| 74: } | 
| 75: } | 
|   | |
| CalcWorkerTwo has been modified to take advantage of the interruptible I/O of BufferedThreadedInputStream (line 13). The InterruptedIOException has been caught in this code simply to print a message (lines 4547) but can be ignored. The stopRequest() method (lines 6370) has been simplified back down to the self-running object templateonly an interrupt() is necessary to unblock a read() . | 
|   | |
| The same CalcClient code can be used with the new CalcServerTwo and CalcWorkerTwo . Listing 15.11 shows possible output from CalcServerTwo . Your output should match very closely with only a message or two swapped. | 
|   | |
| Listing 15.11 Possible Output from CalcServerTwo | 
|   | |
| 1: in CalcServer - ready to accept connections | 
| 2: in CalcServer - about to block waiting for a new connection | 
| 3: in CalcServer - received new connection | 
| 4: in CalcServer - about to block waiting for a new connection | 
| 5: in CalcWorker - about to block waiting to read a double | 
| 6: in CalcWorker - read a double! | 
| 7: in CalcWorker - about to block waiting to read a double | 
| 8: in CalcServer - entering stopRequest() | 
| 9: in CalcServer - putting in a stop request to all the workers | 
| 10: in CalcWorker - entering stopRequest() | 
| 11: in CalcWorker - leaving stopRequest() | 
| 12: in CalcWorker - blocked read was interrupted!!! | 
| 13: in CalcServer - leaving runWork() | 
| 14: in CalcWorker - leaving runWork() | 
|   | |
| The main difference in the output from what was seen before is line 12. Here, a message is printed confirming that an InterruptedIOException was thrown when the blocked thread was interrupted. | 
|  |   | ||
|    Toc    | |||