Wiki Markup |
---|
According to the Java API interface {{java.util.concurrent.ExecutorService}}, method {{shutdownNow()}} documentationDo not submit tasks that do not support interruption using {{Thread.interrupt()}} to a thread pool if it is necessary to shutdown the thread pool or to cancel individual tasks within the thread pool. According to the Java API interface \[[API 06|AA. Java References#API 06]\] the {{java.util.concurrent.ExecutorService.shutdownNow()}} method: |
Attempts to stop all actively executing tasks, halts the processing of waiting tasks, and returns a list of the tasks that were awaiting execution. There are no guarantees beyond best-effort attempts to stop processing actively executing tasks. For example, typical implementations will cancel via
Thread.interrupt()
, so any task that fails to respond to interrupts may never terminate.
Consequently, tasks that do not support interruption using Thread.interrupt()
should not be submitted to a thread pool. Similarly, when attempting to cancel individual tasks within the thread pool using the Future.cancel()
method, ensure that the tasks support interruption.
Noncompliant Code Example (
...
Shutting Down Thread Pools)
This noncompliant code example uses submits the SocketReader
class defined earlier in the Compliant Solution (close socket connection) of the guideline CON26-J. Ensure that threads performing blocking operations can be terminated and submits it as a task to a the thread pool defined declared in class PoolService
.
Code Block | ||
---|---|---|
| ||
public final 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(); public SocketReader(String 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 particular time @Override public void run() { try { synchronized (lock) { readData(); } } catch (IOException ie) { // Forward to handler } } public void readData() throws IOException { String string; try { while ((string = in.readLine()) != null) { // Blocks until end of stream (null) } } finally { shutdown(); } } public void shutdown() throws IOException { socket.close(); } } public final class PoolService { private final ExecutorService pool; public PoolService(int poolSize) { pool = Executors.newFixedThreadPool(poolSize); } public void doSomething() throws InterruptedException, IOException { pool.submit(new SocketReader()); // ... List<Runnable> awaitingTasks = pool.shutdownNow(); } public static void main(String[] args) throws InterruptedException, IOException { PoolService service = new PoolService(5); service.doSomething(); } } public final class SocketReader implements Runnable { private final Socket socket; // ... } |
Because the task does not support interruption through the use of using Thread.interruptedinterrupt()
, there is no guarantee that the shutdownNow()
method will quiickly shutdown the thread pool. Using the shutdown()
method does not fix the problem either, because it waits until all executing tasks have finished.
Similarly, tasks that use some mechanism other than Thread.interrupted()
to determine when to shutdown will be unresponsive to shutdown()
or shutdownNow()
. For instance, tasks that check a volatile flag to determine whether it is safe to shutdown will be unresponsive to these methods. The guideline CON24-J. Do not use Thread.stop() to terminate threads provides more information on using a flag to terminate threads.
Compliant Solution (
...
Submit Interruptible Tasks)
This compliant solution submits the defines an interruptible version of SocketReader
discussed in the Compliant Solution (interruptible channel) of the guideline CON26-J. Ensure that threads performing blocking operations can be terminated, the SocketReader
class, which is instantiated and submitted to the thread pool.
Code Block | ||
---|---|---|
| ||
public final class SocketReader implements Runnable { private final SocketChannel sc; private final Object lock = new Object(); public SocketReader(String 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) { // Forward to handler } } } public final class PoolService { // ... } public final class SocketReader implements Runnable { private final SocketChannel sc; // ... } |
Exceptions
CON31-EX1: Tasks Short-running tasks that execute without blocking may violate are not required to adhere to this guideline.
Risk Assessment
...