java 线程中断

java并没有提供一种直接中断或者停止线程的方法,实际上我们说的线程中断或者取消都是基于一种协作的机制来实现的,所谓协作即调用中断或者取消方法后,线程会通过检测某个状态位来决定是否要退出正在执行的工作,从而来停止线程的执行。应该说线程中断是没有一种统一的处理方案的,正确的线程中断处理方案都需要考虑线程的具体使用的情景。另外线程中断都不是一个立即执行的动作,前面说了是一种协作机制。

下面说说线程的几种使用情景:
1)线程中没有阻塞处理函数,可以使用共享变量机制或者检查当前线程的中断状态。简单的示例代码如下:

class t1 extends Thread {
    public volatile boolean isInterupted = false;
    @Override
    public void run() {
        while (!isInterupted) {
            // do work
            System.out.println("t1 run!");
        }
        System.out.println("t1 exit!");
    }
}

class t2 extends Thread {
    @Override
    public void run() {
        while (!Thread.currentThread().isInterrupted()) {
            // do work
            System.out.println("t2 run!");
        }
        System.out.println("t2 exit!");
    }
}

2)线程中有响应中断的阻塞处理函数,则需要捕获中断异常InteruptedException,需要注意的是捕获这个中断异常后,中断状态位会被清除。若捕获异常的函数是一个内部函数,那这个时候得想好内部函数的处理机制了,你可以抛出这个中断异常(注意中断状态已经没有了,外部必须处理这个中断异常了),你也可以捕获异常后重新设置中断状态位,建议的做法是内部函数不处理异常,直接把异常抛出。示例代码如下:

class t2 extends Thread {
    @Override
    public void run() {
        while (!Thread.currentThread().isInterrupted()) {
            try {
                work();
            } catch (InterruptedException e) {
                e.printStackTrace();
                this.interrupt();
            }
            System.out.println("t2 run!");

        }
        System.out.println("t2 exit!");
    }

    private void work() throws InterruptedException {
        TimeUnit.SECONDS.sleep(5);
    }
}

注意上面的实现捕获异常后,需要重新设置中断异常位,否则这个线程就没有办法正常的中断了,因为线程捕获后中断位已经被清除了,while循环的条件不会为真。

3)JDK1.4版本之后,NewIO中提供的channel方法的阻塞处理,是可以响应中断,只是它收到的不是InterruptedException而是ClosedByInterruptException,这种情况下的处理方式和第2点是一样的。

4)对于普通的IO操作无法响应中断的,我们只能通过另外一种方式来中断线程了,那就是通过关闭IO流的方式来实现。关闭IO流后,它的读或者写阻塞操作就触发IO异常,这时线程可以捕获该异常,然后终止正在执行的线程,来达到我们中断线程运行的目的。示例代码如下:

class t1 extends Thread {
    public volatile FileInputStream fis;
    @Override
    public void run() {
        while (true) {
            try {
                fis.read();
            } catch (IOException e) {
                e.printStackTrace();
                break;
            }
        }
        System.out.println("t1 exit!");
    }
}

5)若是通过线程池框架提交的线程,我们可以使用shutdown或者shutdownNow来关闭线程池从而中断所有线程的执行,当然也可以使用Future的cancle方法来关闭线程,实际上底层调用都是设置了中断异常标志来实现的。

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