Java并发编程实战 之 线程的取消与关闭

任务取消

场景

  • 用户手动取消。
  • 线程超时。
  • 线程提前结束,已经得到结果。
  • 发生错误。
  • 主线程关闭。
  • java没有抢占式的线程停止方式,必须依靠线程本身与外部状态通过协作式的方式停止。

线程中断

  • 通过设置状态位,并在某些方法中去检查这个状态位,但是这些可以响应中断状态的方法,可能被阻塞,例如调用BlockingQueue的put方法。

中断方法

  • 每个线程都由一个静态的中断状态位,interrupt
  • interrupt() 中断线程,但是不清除状态位。
  • interrupted() 清除当前中断状态,并返回之前的值。

一般说来,当可能阻塞的方法声明中有抛出InterruptedException则暗示该方法是可中断的,如BlockingQueue#put、BlockingQueue#take、Object#wait、Thread#sleep等

中断策略

  • 抛出InterruptedException,来通知上一层的代码。
  • 恢复中断状态使上一层代码可以检查到。

通过Future来实现取消

  Futuretask=taskExec.submit(r);
   try{
       task.get(timeout,unit);
   }
   catch (TimeoutExceptione){
     //下面任务会被取消
   }
   catch (ExecutionExceptione){
     //task中抛出的异常;重抛出
     throw launderThrowable(e.getCause());
   }
   finally{
     //如果任务已经结束,是无害的
     task.cancerl(true);
   }
}

处理不可中断的阻塞

  • 不响应中断的方法
    • Socket I/O ,read和write方法,可以通过强行关闭Socket中断。
    • 同步I/O
    • Selector的异步I/O,如果调用select方法的时候阻塞了,可以通过调用close方法或wakeup方法,使
      其抛出ClosedSelectorException
    • 获取一个锁的时候,也不会响应中断,但是Lock的lockInterruptibly,弥补了这些不足,它允许等待锁的同时,可以响应中断。
  • 通过重写Thread的interrupt方法来解决上述的不响应中断的类的中断问题。
package net.jcip.examples;

import java.io.IOException;
import java.io.InputStream;
import java.net.Socket;

/**
 * ReaderThread
 * 

* Encapsulating nonstandard cancellation in a Thread by overriding interrupt * * @author Brian Goetz and Tim Peierls */ public class ReaderThread extends Thread { private static final int BUFSZ = 512; private final Socket socket; private final InputStream in; public ReaderThread(Socket socket) throws IOException { this.socket = socket; this.in = socket.getInputStream(); } 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 */ } } public void processBuffer(byte[] buf, int count) { } }

通过newTaskFor来封装非标准的取消

  • 讲的是 如何扩展Future的cancel方法。
package net.jcip.examples;

import java.io.IOException;
import java.net.Socket;
import java.util.concurrent.*;

import net.jcip.annotations.*;

/**
 * SocketUsingTask
 * 

* Encapsulating nonstandard cancellation in a task with newTaskFor * * @author Brian Goetz and Tim Peierls */ public abstract class SocketUsingTask <T> implements CancellableTask<T> { @GuardedBy("this") 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 newTask() { return new FutureTask(this) { public boolean cancel(boolean mayInterruptIfRunning) { try { SocketUsingTask.this.cancel(); } finally { return super.cancel(mayInterruptIfRunning); } } }; } } interface CancellableTask <T> extends Callable<T> { void cancel(); RunnableFuture newTask(); } @ThreadSafe class CancellingExecutor extends ThreadPoolExecutor { public CancellingExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue workQueue) { super(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue); } public CancellingExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue workQueue, ThreadFactory threadFactory) { super(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue, threadFactory); } public CancellingExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue workQueue, RejectedExecutionHandler handler) { super(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue, handler); } public CancellingExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue workQueue, ThreadFactory threadFactory, RejectedExecutionHandler handler) { super(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue, threadFactory, handler); } protected RunnableFuture newTaskFor(Callable callable) { if (callable instanceof CancellableTask) return ((CancellableTask) callable).newTask(); else return super.newTaskFor(callable); } }

你可能感兴趣的:(多线程,java)