Java Should There Be Just One Thread to Read From Socket
Threads and tasks that block on operations involving network or file I/O must provide callers with an explicit termination mechanism to prevent denial-of-service (DoS) vulnerabilities.
Noncompliant Code Example (Blocking I/O, Volatile Flag)
This noncompliant lawmaking case uses a volatile done
flag to point it whether is rubber to shut down the thread, as suggested in THI05-J. Do not use Thread.stop() to end threads. However, when the thread is blocked on network I/O as a upshot of invoking the readLine()
method, it cannot respond to the newly gear up flag until the network I/O is complete. Consequently, thread termination may exist indefinitely delayed.
// Thread-safe class public final form SocketReader implements Runnable { private last Socket socket; individual final BufferedReader in; private volatile boolean done = false; private final Object lock = new Object(); public SocketReader(Cord host, int port) throws IOException { this.socket = new Socket(host, port); this.in = new BufferedReader( new InputStreamReader(this.socket.getInputStream()) ); } // Only one thread can use the socket at a item time @Override public void run() { try { synchronized (lock) { readData(); } } catch (IOException ie) { // Frontwards to handler } } public void readData() throws IOException { String string; while (!done && (string = in.readLine()) != nada) { // Blocks until terminate of stream (null) } } public void shutdown() { done = true; } public static void main(String[] args) throws IOException, InterruptedException { SocketReader reader = new SocketReader("somehost", 25); Thread thread = new Thread(reader); thread.start(); Thread.sleep(1000); reader.shutdown(); // Close downwards the thread } }
Noncompliant Lawmaking Example (Blocking I/O, Interruptible)
This noncompliant code example is like to the preceding instance but uses thread suspension to close down the thread. Network I/O on a java.net.Socket
is unresponsive to thread intermission.
// Thread-rubber course public final form SocketReader implements Runnable { // Other methods... public void readData() throws IOException { String string; while (!Thread.interrupted() && (cord = in.readLine()) != cipher) { // Blocks until cease of stream (zero) } } public static void main(Cord[] args) throws IOException, InterruptedException { SocketReader reader = new SocketReader("somehost", 25); Thread thread = new Thread(reader); thread.start(); Thread.sleep(g); thread.interrupt(); // Interrupt the thread } }
Compliant Solution (Close Socket Connection)
This compliant solution terminates the blocking network I/O by closing the socket in the shutdown()
method. The readLine()
method throws a SocketException
when the socket is closed, consequently allowing the thread to proceed. Note that it is incommunicable to keep the connection alive while simultaneously halting the thread both cleanly and immediately.
public final course SocketReader implements Runnable { // Other methods... public void readData() throws IOException { String cord; endeavour { while ((string = in.readLine()) != cypher) { // Blocks until end of stream (null) } } finally { shutdown(); } } public void shutdown() throws IOException { socket.close(); } public static void main(String[] args) throws IOException, InterruptedException { SocketReader reader = new SocketReader("somehost", 25); Thread thread = new Thread(reader); thread.start(); Thread.sleep(k); reader.shutdown(); } }
After the shutdown()
method is called from chief()
, the finally
block in readData()
executes and calls shutdown()
again, closing the socket for a second time. Notwithstanding, when the socket has already been closed, this second phone call does nil.
When performing asynchronous I/O, a coffee.nio.channels.Selector
can be unblocked past invoking either its close()
or its wakeup()
method.
When additional operations must be performed after emerging from the blocked state, apply a boolean
flag to indicate pending termination. When supplementing the lawmaking with such a flag, the shutdown()
method should also set the flag to simulated then that the thread can cleanly exit from the while
loop.
Compliant Solution (Interruptible Aqueduct)
This compliant solution uses an interruptible channel, java.nio.channels.SocketChannel
, instead of a Socket
connection. If the thread performing the network I/O is interrupted using the Thread.interrupt()
method while it is reading the information, the thread receives a ClosedByInterruptException
, and the aqueduct is closed immediately. The thread'due south interrupted condition is also set.
public terminal class SocketReader implements Runnable { private final SocketChannel sc; individual final Object lock = new Object(); public SocketReader(Cord host, int port) throws IOException { sc = SocketChannel.open(new InetSocketAddress(host, port)); } @Override public void run() { ByteBuffer buf = ByteBuffer.allocate(1024); try { synchronized (lock) { while (!Thread.interrupted()) { sc.read(buf); // ... } } } catch (IOException ie) { // Forrard to handler } } public static void master(String[] args) throws IOException, InterruptedException { SocketReader reader = new SocketReader("somehost", 25); Thread thread = new Thread(reader); thread.outset(); Thread.sleep(m); thread.interrupt(); } }
This technique interrupts the current thread. However, it stops the thread only because the code polls the thread's interrupted condition with the Thread.interrupted()
method and terminates the thread when it is interrupted. Using a SocketChannel
ensures that the condition in the while
loop is tested every bit soon as an interruption is received, fifty-fifty though the read is ordinarily a blocking operation. Similarly, invoking the interrupt()
method of a thread blocked on a java.nio.channels.Selector
also causes that thread to awaken.
Noncompliant Code Example (Database Connectedness)
This noncompliant code example shows a thread-safe DBConnector
grade that creates i JDBC connection per thread. Each connection belongs to ane thread and is not shared by other threads. This is a common utilise instance considering JDBC connections are intended to be unmarried-threaded.
public final class DBConnector implements Runnable { private final String query; DBConnector(String query) { this.query = query; } @Override public void run() { Connection connection; effort { // Username and countersign are hard coded for brevity connection = DriverManager.getConnection( "jdbc:driver:name", "username", "password" ); Argument stmt = connection.createStatement(); ResultSet rs = stmt.executeQuery(query); // ... } catch (SQLException e) { // Forwards to handler } // ... } public static void principal(String[] args) throws InterruptedException { DBConnector connector = new DBConnector("suitable query"); Thread thread = new Thread(connector); thread.start(); Thread.sleep(5000); thread.interrupt(); } }
Database connections, similar sockets, lack inherent interruptibility. Consequently, this design fails to support the customer's attempts to cancel a task by endmost the resources when the corresponding thread is blocked on a long-running query, such as a bring together.
Compliant Solution (Argument.abolish()
)
This compliant solution uses a ThreadLocal
wrapper around the connection so that a thread calling the initialValue()
method obtains a unique connection instance. This approach allows provision of a cancelStatement()
then that other threads or clients tin interrupt a long-running query when required. The cancelStatement()
method invokes the Statement.cancel()
method.
public final form DBConnector implements Runnable { private final Cord query; private volatile Statement stmt; DBConnector(String query) { this.query = query; } private static final ThreadLocal<Connection> connectionHolder = new ThreadLocal<Connection>() { Connection connectedness = null; @Override public Connection initialValue() { try { // ... connection = DriverManager.getConnection( "jdbc:driver:name", "username", "password" ); } catch (SQLException e) { // Frontward to handler } return connexion; } }; public Connection getConnection() { render connectionHolder.get(); } public boolean cancelStatement() { // Allows client to cancel statement Statement tmpStmt = stmt; if (tmpStmt != null) { endeavor { tmpStmt.cancel(); return truthful; } catch (SQLException e) { // Forwards to handler } } return false; } @Override public void run() { try { if (getConnection() != null) { stmt = getConnection().createStatement(); } if (stmt == zilch || (stmt.getConnection() != getConnection())) { throw new IllegalStateException(); } ResultSet rs = stmt.executeQuery(query); // ... } take hold of (SQLException e) { // Frontwards to handler } // ... } public static void main(Cord[] args) throws InterruptedException { DBConnector connector = new DBConnector("suitable query"); Thread thread = new Thread(connector); thread.offset(); Thread.sleep(5000); connector.cancelStatement(); } }
The Argument.cancel()
method cancels the query, provided the database management organisation (DBMS) and driver both support cancellation. It is impossible to cancel the query if either the DBMS or the driver fail to support counterfoil.
According to the Java API, Interface Statement
documentation [API 2014]
By default, simply 1
ResultSet
object perArgument
object can be open at the same time. Equally a result, if the reading of 1ResultSet
object is interleaved with the reading of another, each must have been generated by differentArgument
objects.
This compliant solution ensures that only one ResultSet
is associated with the Statement
belonging to an instance, and, consequently, simply ane thread tin access the query results.
Adventure Cess
Failure to provide facilities for thread termination tin crusade nonresponsiveness and DoS.
Rule | Severity | Likelihood | Remediation Cost | Priority | Level |
---|---|---|---|---|---|
THI04-J | Low | Probable | Medium | P4 | L3 |
Bibliography
krogerreplads1943.blogspot.com
Source: https://wiki.sei.cmu.edu/confluence/display/java/THI04-J.+Ensure+that+threads+performing+blocking+operations+can+be+terminated
0 Response to "Java Should There Be Just One Thread to Read From Socket"
Post a Comment