Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.
Comment: experimenting by making the classes thread-safe...then this can be an exception to CON20

...

Code Block
bgColor#FFcccc
class SocketReader implements Runnable { // Thread-safe class
  private final Socket socket;
  private final BufferedReader in;
  private volatile boolean done = false;
  private final Object lock = new Object();
  private boolean isRunning = false; // Reduces the need to synchronize time consuming operations
  public static 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 execute(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();
  }
}

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, an unchecked exception is thrown.

Noncompliant Code Example (blocking Noncompliant Code Example (blocking IO, interruptible)

This noncompliant code example uses thread interruption to indicate that it is safe to shutdown the thread, as suggested in CON13-J. Ensure that threads are stopped cleanly. However, this is not useful because the thread is blocked on some network IO as a consequence of using the readLine() method. Network I/O is not responsive to thread interruption.

Code Block
bgColor#FFcccc
class SocketReader implements Runnable { // Thread-safe class
  // ...
  
  public void execute() throws IOException {
    String string;
    while (!Thread.interrupted() && (string = in.readLine()) != null) { 
      // Blocks until end of stream (null)
    }
  }
  
  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();
  }
}

...

Code Block
bgColor#ccccff
class SocketReader implements Runnable {
  private final SocketChannel sc;
  private final Object lock = new Object();
  private boolean isRunning = false;
  private class MultipleUseException extends RuntimeException {};
  
  public SocketReader() throws IOException {
    sc = SocketChannel.open(new InetSocketAddress("somehost", 25));    
  }
  
  public void run() {
    synchronized (lock) {;
  
  public SocketReader() ifthrows (isRunning)IOException {
    sc    throw = SocketChannel.open(new MultipleUseException();
InetSocketAddress("somehost", 25));    
  }
  
  public void isRunning = true;
    }
run() {
    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();
  }
}

...

Code Block
bgColor#FFcccc
class DBConnector implements Runnable {
  final String query;
  
  DBConnector(String query) {
    this.query = query; 
  }
	
  public void run() {
    Connection con;
    try {
      // Username and password are hard coded for brevity
      con = DriverManager.getConnection("jdbc:driver:name", "username","password");  
      Statement stmt = con.createStatement();
      ResultSet rs = stmt.executeQuery(query);
    } catch (SQLException e) {
      // Forward to handler
    }
    // ... 
  }  


  public static void main(String[] args) throws InterruptedException {
    DBConnector connector = new DBConnector(/* "suitable query */");
    Thread thread = new Thread(connector);
    thread.start();
    Thread.sleep(5000);
    thread.interrupt();
  }
}

...