背景:公司抽奖,java写的抽奖程序,待领导喊完开始后,疯狂输出,一段时间后,领导喊 "停......" ,台下一阵哄笑,画面异常尴尬。
过时危险的方法不再今天讨论之内,读者自行补充即可( Thread.stop, Thread.suspend, Thread.resume 和Runtime.runFinalizersOnExit).
停止线程的方法有四种:
1 基于用户自定义的状态字段
2 基于线程的中断机制(并不是只要发了中断请求,运行线程就会第一时间停止,中断机制是一种协程,类似求人办事)
3 前两种相结合
4 最终方案
1 基于用户自定义的状态字段
实现方式: 1>自定义boolean性的字段,记住最好用volatile修改,保证可见性
2>对外提供实例方法,用于修改修改状态字段
3>判断状态(不限于while ,if......),符合条件,结束程序
缺点:对于简单的业务代码适用,稍微复杂的场景就不行了,基本上没用武之地。
public class InterrputedTest {
public static void main(String[] args) {
MainTask mainTask = new MainTask();
Thread t = new Thread(mainTask);
t.start();
try {
TimeUnit.SECONDS.sleep(10);
mainTask.setStop();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
class MainTask implements Runnable {
private volatile boolean run = true;
public void run() {
while (run) {
System.out.println("正在运行");
}
}
public void setStop() {
run = false;
}
}
2 基于线程的中断机制
实现方式: 1>在工作线程中响应中断异常,切记不要自己吃掉异常
2>外部调用实例线程的interrupt()方法,设置中断状态
3>判断状态(不限于while ,if......),符合条件Thread.currentThread().isInterrupted()或者Thread.interrupted(),结束程序(两种方法的区别是:isInterrupted()单纯的判断线程的中断状态,静态方法interrupted()不但返回当前状态并且会重新初始化为false)
缺点:只适用于响应中断异常(InterruptedException)的程序,不能中断其他异常程序。
public class InterrputedTest {
public static void main(String[] args) {
MainTask mainTask = new MainTask();
Thread t = new Thread(mainTask);
t.start();
try {
TimeUnit.SECONDS.sleep(10);
t.interrupt();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
class MainTask implements Runnable {
public void run() {
while (Thread.interrupted()) {
try {
TimeUnit.SECONDS.sleep(10);
System.out.println("正在运行");
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
break;
}
}
}
}
3 前两种相结合
实现方式:结合前两种方案
缺点:不能中断其他异常程序,例如IO线程,socket线程等。
public class InterrputedTest {
public static void main(String[] args) {
MainTask mainTask = new MainTask();
Thread t = new Thread(mainTask);
t.start();
try {
TimeUnit.SECONDS.sleep(10);
t.interrupt();
mainTask.stop();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
class MainTask implements Runnable {
private volatile boolean run=true;
public void run() {
while (run && !Thread.interrupted()) {
try {
TimeUnit.SECONDS.sleep(10);
System.out.println("正在运行");
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
break;
}
}
}
public void stop(){
this.run=false;
}
}
4 最终方案
如果想要完美的快速的停止一个线程,前三种方案并不能达到目的,再采用第三种方案的前提下,我们需要思考几个问题。
1> 任务是否可以拆分?如果可以拆分利用循环多次监测,每次循环判断条件,加快停止的时间。
2>对于不能再拆分的耗时任务怎么处理?能响应中断请求的利用中断异常,不能响应中断异常的阻塞,需要特定处理,例如IO操作可以关闭流,让其抛出异常结束,socket需要关闭流,让其抛出异常结束。(这一类针对能抛出异常的处理方案)
3>阻塞的代码的可以参考第二条,非阻塞的代码,怎么弄,例如占用cpu的耗时操作,排序?可以通过多处增加状态的判断(本方案使用于不能抛出异常的处理方案,运行效率和响应速度需要作出权衡)