chapter7 取消与关闭1

来源:互联网 发布:php获取上上个文件夹名 编辑:程序博客网 时间:2024/06/08 00:33
    java没有提供任何一种机制来安全的终止线程。但它提供了中断,这是一种协作机制,能够使一个线程终止另一个线程的当前工作。
    这种协作机制是必要的,我们很少希望某个任务、线程或者服务立即停止,因为这种立即停止或使共享的数据结构处于不一致的状态。当需要停止时,应该首先清除当前正在执行的工作,然后再结束。

    1、使用volatile来保存取消状态
@ThreadSafepublic class PrimeGenerator implements Runnable {    private static ExecutorService exec = Executors.newCachedThreadPool();    @GuardedBy("this") private final List<BigInteger> primes            = new ArrayList<BigInteger>();    private volatile boolean cancelled;    public void run() {        BigInteger p = BigInteger.ONE;        while (!cancelled) {            p = p.nextProbablePrime();            synchronized (this) {                primes.add(p);            }        }    }    public void cancel() {        cancelled = true;    }    public synchronized List<BigInteger> get() {        return new ArrayList<BigInteger>(primes);    }    static List<BigInteger> aSecondOfPrimes() throws InterruptedException {        PrimeGenerator generator = new PrimeGenerator();        exec.execute(generator);        try {            SECONDS.sleep(1);        } finally {            generator.cancel();        }        return generator.get();    }}
     2、中断
      在线程调用阻塞方法时,volatile变量的检查标志就可能无法被执行到,线程会一直阻塞,这种情况下,需要使用中断。
      线程中断是一种协作机制,线程可以通过这种机制来通知另一个线程,告诉它在合适的或者可能的情况下停止当前的工作,并转而执行其他工作。
      interrupt方法可以中断目标线程,isInterrupted方法可以获得线程的中断状态,静态interrupted方法可以清除当前线程的中断状态,并返回它之前的值。
     阻塞库方法,例如sleep和wait等方法,都会检查线程何时中断,并在发现中断时提前返回。它们在响应中断时执行的操作包括:清除中断状态,抛出InterruptedException。JVM不能保证阻塞方法响应中断的速度,但在实际情况中,响应数据还是非常快的。
    通常,中断是实现取消的最合理方式。
   不能屏蔽InterruptedException,例如在catch块中捕获异常却不处理。除非代码中实现了线程的中断策略。
   中断不会影响ThreadPoolExecutor线程池,中断一个线程之后,线程池会创建一个新的线程。
   
   3、通过future来实现取消
    future可以设置任务执行超时时间,如果超时则抛出异常,此时可以调用cancel方法来取消任务 。
    public class TimedRun {
    private static final ExecutorService taskExec = Executors.newCachedThreadPool();    public static void timedRun(Runnable r,                                long timeout, TimeUnit unit)            throws InterruptedException {        Future<?> task = taskExec.submit(r);        try {            task.get(timeout, unit);        } catch (TimeoutException e) {            // task will be cancelled below        } catch (ExecutionException e) {            // exception thrown in task; rethrow            throw launderThrowable(e.getCause());        } finally {            // Harmless if task already completed            task.cancel(true); // interrupt if running        }    }}
4、不可中断的阻塞
        并不是所有可阻塞方法都能响应中断:如果一个线程由于执行同步Socket I/O或者等待获得内置锁而阻塞,那么中断请求除了设置中断状态,没有其它任何作用。
        这种情况下,可以通过改写interrupt方法将非标准的取消操作封装在Thread中。
      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) {    }}
原创粉丝点击