並不是所有的阻塞都是可中斷的, 比如InputStream.read方法. 在檢測到輸入數據可用, 到達流末尾或者拋出異常前, 該方法一直阻塞. 而且阻塞的時候不會檢查中斷標記, 所以中斷線程無法使read從阻塞狀態返回. 但是關閉流可以使得read方法拋出異常, 從而從阻塞狀態返回.
- public class ReaderThread extends Thread {
- private static final int BUFSZ = 1024;
- private final Socket socket;
- private final InputStream in;
- public ReaderThread(Socket socket) throws IOException {
- this.socket = socket;
- this.in = socket.getInputStream();
- }
- // 覆蓋Thread類的interrupt方法, 加入關閉socket的代碼
- // 如果發生中斷時, 線程阻塞在read方法上, socket的關閉會導致read方法拋出SocketException, 然後run方法運行完畢
- public void interrupt() {
- try {
- socket.close();
- } catch (IOException ignored) {
- } finally {
- super.interrupt();
- }
- }
- public void run() {
- try {
- byte[] buf = new byte[BUFSZ];
- while (true) {
- int count = in.read(buf);
- if (count < 0)
- break;
- else if (count > 0)
- processBuffer(buf, count);
- }
- } catch (IOException e) { /* Allow thread to exit */
- }
- }
- private void processBuffer(byte[] buf, int count) {
- //...
- }
- }
如果task並非在自己創建的線程裏運行, 而是提交給線程池運行的話, 就無法使用上例的方式處理不可中斷阻塞了. 之前有過分析, 對於提交給線程池執行的task, 應該通過Future.cancel方法提前終止task的運行, 所以可以考慮重寫Future.cancel方法, 在其中加入關閉socket的操作. Future對象是由submit方法返回的, 其源代碼如下:
- public <T> Future<T> submit(Callable<T> task) {
- if (task == null)
- throw new NullPointerException();
- RunnableFuture<T> ftask = newTaskFor(task);
- execute(ftask);
- return ftask;
- }
可知submit方法返回的Future對象是調用newTaskFor方法獲得的:
- protected <T> RunnableFuture<T> newTaskFor(Callable<T> callable) {
- return new FutureTask<T>(callable);
- }
newTaskFor方法被聲明爲protected, 所以我們可以通過繼承覆蓋該方法, 返回自定義的Future對象.
首先將需要覆蓋的2個方法定義在接口中:
- public interface CancellableTask<T> extends Callable<T> {
- void cancel();
- RunnableFuture<T> newTask();
- }
然後讓task類實現CancellableTask接口:
- public abstract class SocketUsingTask<T> implements CancellableTask<T> {
- private Socket socket;
- protected synchronized void setSocket(Socket s) {
- socket = s;
- }
- public synchronized void cancel() {
- try {
- if (socket != null)
- socket.close();
- } catch (IOException ignored) {
- }
- }
- public RunnableFuture<T> newTask() {
- return new FutureTask<T>(this) {
- // 定義FutureTask的匿名內部類, 並覆蓋cancel方法, 向其中加入關閉socket的操作
- public boolean cancel(boolean mayInterruptIfRunning) {
- try {
- SocketUsingTask.this.cancel();
- } finally {
- return super.cancel(mayInterruptIfRunning);
- }
- }
- };
- }
- }
接着繼承ThreadPoolExecutor類並覆蓋newTaskFor方法, 讓該方法返回自定義的FutureTask對象:
- public class CancellingExecutor extends ThreadPoolExecutor {
- // ...
- protected <T> RunnableFuture<T> newTaskFor(Callable<T> callable) {
- // 如果callable是CancellableTask對象, 那麼就返回自定義的FutureTask(通過調用其newTaskFor方法實現)
- if (callable instanceof CancellableTask)
- return ((CancellableTask<T>) callable).newTask();
- else
- return super.newTaskFor(callable);
- }
- }
測試代碼:
- public static void main(String[] args) {
- CancellingExecutor executor = new CancellingExecutor();
- SocketUsingTask task = new SocketUsingTask();
- task.setSocket(new Socket("www.baidu.com", 80));
- Future<V> future = executor.submit(task);
- future.cancel(true);
- }