在java编程中我们不可避免的要使用到并发编程.假设我们现在有一个这样的需求,一个线程需要完成一个任务,但是任务执行的过程中,需要停止. 在早期的JDK版本中提供了stop suspend等方法.但是现在已经废弃掉了,因为他可能会引起某些安全问题.故我们可以认为java没有提供线程终止的机制. 所以一般情况下线程的终止是等到起任务执行完毕,然后自然而然的停止掉. 下面我们探讨两种停止的方法.

一,标志位
假设一个线程在执行过程中存在一个循环,我们预先设置一个标志位,这个标志位代表着线程是否结束,那么每次循环都去检查标志位是否发生改变,如果改变就结束当前线程,如果没有改变,就继续执行.

public class FlagExitThread {

    public static void main(String[] args) {
        FlagThread ft = new FlagThread();
        ft.start();
        try {

            Thread.sleep(100);
            //主线程睡眠100毫秒后, 将退出标志位设置为true,让线程退出
            ft.setExit(true);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

}

class FlagThread extends Thread {
    //标志位,代表当前线程是否应该结束,如果需要结束,将isExit设置为true即可.
    private boolean isExit;
    private int counter ;
    @Override
    public void run() {
        //每次循环都检测标志位是否发生改变
        while(!isExit){
            counter++;
            System.out.println(Thread.currentThread().getName()+"  "+counter );
        }
        System.out.println("退出循环,线程结束");
    }

    public boolean isExit() {
        return isExit;
    }

    public void setExit(boolean isExit) {
        this.isExit = isExit;
    }

}

运行结果:

...........
Thread-0  556
Thread-0  557
Thread-0  558
Thread-0  559
Thread-0  560
Thread-0  561
退出循环,线程结束

由上面我们可以看到,通过标志位的方法我们可以很自然和温柔随和的把一个线程终止掉.java中没有一种安全的抢占式方法来停止线程,因为也就没有安全的抢占式方法来停止线程.但是他有一种协作式的机制,是请求取消的任务和代码都遵循一种协商好的协议.,设置”已经请求取消”标志,而任务将定时的查看该标志.

但是我们通过上面的示例发现,使用上面的方法线程一直在运行,处于active(“活”)的状态,如果调用sleep或者wait()方法,线程将会处于睡眠或者阻塞状态那么这种方法将会不起作用——-任务可能永远不会检查取消标志,因此永远无法结束.那么我们就探讨下面的方式.

二,InterruptedException方法.
当线程调用了sleep或者wait方法后,处于阻塞状态,他可能被外部调用interrupt方法打断,抛出一个interrupt异常.那么我们可以对这个InterruptException进行捕获,然后结束线程.

public class InterruptedThreadDemo {

    public static void main(String[] args) {

        // 子线程开启
        ThreadTerminal tt = new ThreadTerminal();
        tt.start();

        try {
            // 主线程休息3s,然后打断子线程
            Thread.sleep(3000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        // 打断子线程
        tt.interrupt();
    }
}

class ThreadTerminal extends Thread {
    private int counter = 0;

    public void run() {
        synchronized (this) {
            while (true) {

                System.out.println("time = " + System.currentTimeMillis());
                counter++;
                try {
                    if (counter == 5) {
                        // 使线程处于阻塞状态
                        wait();
                    }
                } catch (InterruptedException e) {
                    // 捕获InterruptedException,然后退出程序
                    System.out.println("捕获到InterruptedException , 线程结束");
                    return;
                }
            }

        }
    }
}

结果是:

time = 1429807476957
time = 1429807476957
time = 1429807476958
time = 1429807476958
time = 1429807476958
捕获到InterruptedException , 线程结束

当我们使用上面的中断机制时候我们必须明确下面几点内容:
1,每个线程都有一个boolean类型的中断状态.当中断线程时,这个线程的中断状态将被设置为true.
2,interrupt方法能够中断目标线程,而isInterrupted方法能返回目标线程的中断状态.静态的interrupted方法将清除当前线程的中断状态,并返回它之前的值,这也是清除中断状态的唯一方法.
3,响应中断执行的操作: 清除中断状态, 抛出InterruptedException,表示阻塞操作由于中断提前结束.JVM并不能保证阻塞方法检测到中断的速度,但在实际情况中响应速度还是非常快的.

4,调用interrupt并不意味着立即停止目标线程正在进行的工作,而只是传递了请求中断的消息.

5,一般而言,中断是实现取消的最合理方式