Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.

...

Code Block
bgColor#FFcccc
class SocketReader implements Runnable {
  private final Socket socket;
  private final BufferedReader in;
  private volatile boolean done = false;
  private volatilefinal Object lock = new Object();
  private boolean isRunning = false;
  public privatestatic class MultipleUseException extends RuntimeException {};

  public SocketReader() throws IOException {
    this.socket = new Socket("somehost", 25);
    this.in = new BufferedReader(new InputStreamReader(this.socket.getInputStream()));
  }
  
  // Only one thread can use the socket at a particular time
  public void run() {
    try {
      synchronized (lock) {
        if (isRunning) {
          throw new MultipleUseException();
        }
        isRunning = true;
      }
      execute();
    } catch (IOException ie) {
      // Forward to handler
    }
  }

  public void execute() throws IOException {
    String string;
    while (!done && (string = in.readLine()) != null) {
      // Blocks until end of stream (null)
    }
  }

  public void shutdown() {
    done = true;
  }

  public static void main(String[] args) throws IOException, InterruptedException {
    SocketReader reader = new SocketReader();
    Thread thread = new Thread(reader);
    thread.start();
    Thread.sleep(1000);
    reader.shutdown();
  }
}
sleep(1000);
    reader.shutdown();
  }
}

Note that the Runnable object prevents itself from being run in multiple threads using an isRunning() flag. If one thread tries to invoke run() after another thread has already done so, the method will exit with an exception. This exception is not recoverable, as it indicates a bug in the proper usage of this class, and hence, it may be unchecked.

Noncompliant Code Example (blocking IO, interruptible)

...

Code Block
bgColor#ccccff
class SocketReader implements Runnable {
  private final SocketChannel sc;
  private final Object lock = new Object();
  private volatile boolean isRunning = false;
  private class MultipleUseException extends RuntimeException {};
  
  public SocketReader() throws IOException {
    sc = SocketChannel.open(new InetSocketAddress("somehost", 25));    
  }
  
  public void run() {
    synchronized (lock) {
      if (isRunning) {
        throw new MultipleUseException();
      }
      isRunning = true;
    }

    ByteBuffer buf = ByteBuffer.allocate(1024);
    try {
      synchronized (lock) {
        while (!Thread.interrupted()) {
          sc.read(buf);
          // ...
        }
      }
    } catch (IOException ie) {
      // Forward to handler
    }
  }

  public static void main(String[] args) throws IOException, InterruptedException {
    SocketReader reader = new SocketReader();
    Thread thread = new Thread(reader);
    thread.start();
    Thread.sleep(1000);
    thread.interrupt();
  }
}

...