...
Code Block |
---|
|
class DBConnector implements Runnable {
final String query;
DBConnector(String query) {
this.query = query;
}
private static ThreadLocal<Connection> connectionHolder = new ThreadLocal<Connection>() {
Connection connection = null;
@Override public Connection initialValue() {
try {
// Username and password are hard coded for brevity
connection = DriverManager.getConnection
("jdbc:driver:name", "username","password");
} catch (SQLException e) {
// Forward to handler
}
return connection;
}
@Override public void set(Connection con) {
if(connection == null) { // Shuts down connection when null value is passed
try {
connection.close();
} catch (SQLException e) {
// Forward to handler
}
} else {
connection = con;
}
}
};
public static Connection getConnection() {
return connectionHolder.get();
}
public static void shutdownConnection() { // Allows client to close connection anytime
connectionHolder.set(null);
}
public void run() {
Connection dbConnection = getConnection();
Statement stmt;
try {
stmt = dbConnection.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);
connector.shutdown();
}
}
|
Noncompliant Code Example (Interrupting thread executing in thread pool)
This noncompliant code example uses a runnable task shown below:
Code Block |
---|
public class Task implements Runnable {
@Override public void run() {
try {
Thread.sleep(10000); // Do some time consuming task
} catch(InterruptedException ie) {
// Forward to handler
}
}
}
|
The doSomething()
method of class PoolService
submits the task to a thread pool. It carries out the task and if an exception results during the execution of the code in the try
block, it interrupts the thread in an attempt to cancel it.
Code Block |
---|
|
class PoolService {
private final ExecutorService pool;
public PoolService(int poolSize) {
pool = Executors.newFixedThreadPool(poolSize);
}
public void doSomething() throws InterruptedException {
Thread thread = new Thread(new Task());
try {
pool.submit(thread);
// ...
} catch(Throwable t) {
thread.interrupt();
// Forward to handler
}
}
}
|
Wiki Markup |
---|
However, the interruption has no effect on the execution of the task because it is executing in a thread pool. Furthermore, note that it is unknown which tasks would be running in the thread pool at the time the interruption notification is delivered \[[Goetz 06|AA. Java References#Goetz 06]\]. |
Compliant Solution (Cancel using the Future)
This compliant solution obtains the return value of the task (future) and invokes the cancel()
method on it.
Code Block |
---|
|
public class PoolService {
private final ExecutorService pool;
public PoolService(int poolSize) {
pool = Executors.newFixedThreadPool(poolSize);
}
public void doSomething() throws InterruptedException {
Thread thread = new Thread(new Task());
try {
Future<?> future = pool.submit(thread);
} catch(Throwable t) {
future.cancel(true);
// Forward to handler
}
}
}
|
Risk Assessment
Trying to force thread shutdown can result in inconsistent object state and corrupt the object. Critical resources may also leak if cleanup operations are not carried out as required.
...