如何优雅去的去终止一个线程,这也是使用多线程应该考虑的问题
这个优雅就是让一个线程接手到了终止指令,让其可以料理完后事,安稳的被终止掉了
那么,可以采用两阶段终止模式,就是将终止过程分别为了两个过程,一阶段就是T1向T2发送终止指令,二阶段用于响应终止指令,即真正的终止线程的运行
在Java的Thread使用过程中,终止的方式之前也说过,可以通过stop()或者interrupt()方法,但是stop()太过于粗暴了,不适合直接的使用,
那么我们使用interrupt()方法,在使用的时候,需要注意一点,就是线程所处于的状态,
线程可以从Runnable状态转换为终止状态,但是在线程的生命周期中,除了运行状态还有休眠状态
那么interrupt()方法,会先设置一个标志位,然后来进行唤醒线程
线程检查符合标志位了,进行退出run()方法,响应终止指令
那么可以简单的总结为,
1.使用interrupt()方法去唤醒线程
2.线程检测标志位去终止
我们用一个简单的代码去实现终止操作
下面就是使用了start()方法去启动线程,然后使用stop去终止线程
class Proxy {
boolean started = false;
//采集线程
Thread rptThread;
//启动采集功能
synchronized void start(){
//不允许同时启动多个采集线程
if (started) {
return;
}
started = true;
rptThread = new Thread(()->{
while (!Thread.currentThread().isInterrupted()){
//省略采集、回传实现
report();
//每隔两秒钟采集、回传一次数据
try {
Thread.sleep(2000);
} catch (InterruptedException e){
//重新设置线程中断状态
Thread.currentThread().interrupt();
}
}
//执行到此处说明线程马上终止
started = false;
});
rptThread.start();
}
//终止采集功能
synchronized void stop(){
rptThread.interrupt();
}
}
上述代码,就是利用一个interrupt()唤醒了等待线程,并抛出了InterruptedException异常,然后捕捉到了异常,说明是运行中了,由于异常捕获机制,会清除了中断异常,需要我们重新设置了中断状态,进行终止
但是在实际生活中,需要谨慎的使用,因为有些第三方的类库不会抛出中断异常,或者捕获到Interrupted异常不会设置中断状态
导致不会正常终止,所以最好还是自己设置一个线程终止的标志位,使用isDown作为一个标志位,只要终止,就将其设置为改变
class Proxy {
//线程终止标志位
volatile boolean terminated = false;
boolean started = false;
//采集线程
Thread rptThread;
//启动采集功能
synchronized void start(){
//不允许同时启动多个采集线程
if (started) {
return;
}
started = true;
terminated = false;
rptThread = new Thread(()->{
while (!terminated){
//省略采集、回传实现
report();
//每隔两秒钟采集、回传一次数据
try {
Thread.sleep(2000);
} catch (InterruptedException e){
//重新设置线程中断状态
Thread.currentThread().interrupt();
}
}
//执行到此处说明线程马上终止
started = false;
});
rptThread.start();
}
//终止采集功能
synchronized void stop(){
//设置中断标志位
terminated = true;
//中断线程rptThread
rptThread.interrupt();
}
}
增加了一个标志位,将线程终止了
那么关于单一线程之后,关于线程池如何进行终止,常见提供的方法为,shutdown(),shutdownNow() 两个方法有什么区别
shutDown()方式是一个保守的方法,就是接收到showdown()方法之后,拒绝新的任务,等待线程池所有任务(包括阻塞队列的任务)完成后关闭线程池
shutdownNow()方法相对激进了,就是接收到了shoudownNow()方法之后,就会中断所有正在执行的代码,而且清空阻塞队列,不过可以将剥夺了执行权的任务作为返回值进行返回,比较暴力,不推荐使用
如果线程支持后续以补偿的方式重新执行,倒是可以使用shutdownNow()方法去执行