在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,一般而言,中断是实现取消的最合理方式