接上一篇:Thread的Interrupt()源代码分析(7)
在Thread中stop()方法已经被不推荐使用了,那么我们该如何去以一种优美的姿态去结束掉它呢?
首先,我们能否在线程里给一个标识,标识改变就结束掉它呢?请看最基础的结束线程的方式:
class ThreadDemo02 implements Runnable{
private boolean flag = true;
@Override
public void run() {
while (flag){
//停止线程---让run方法结束,改变运行标志也就意味着线程结束
System.out.println(Thread.currentThread().getName()+"...run");
}
}
public void changeFlag(){
flag = false;
}
}
public class StopThread {
public static void main(String[] args) throws InterruptedException {
ThreadDemo02 t = new ThreadDemo02();
Thread t1 = new Thread(t);
Thread t2 = new Thread(t);
t1.start();
t2.start();
int num = 0;
while (true){
if(num++ == 6000){
t.changeFlag();
break;
}
num++;
System.out.println(Thread.currentThread().getName()+"...停止..."+num);
}
}
这个是比较简单的结束方式,但是会存在问题,当线程出于冻结状态就不会读取到标记,那么线程就不会结束。
接下来我们来看第二种实现方式,原理是线程在运行的时候会判断该线程是否为中断状态,如果不是,就往下执行,而且当线程为blocked状态时,使用interrupt()则会catch捕获到,然后也会结束线程。
class ThreadDemo06 implements Runnable{
@Override
public void run(){
//停止线程---让run方法结束,改变运行标志也就意味着线程结束
/*
* 特殊情况:当线程出于冻结状态就不会读取到标记,那么线程就不会结束
* 解决方案:把需要冻结的线程进行清除状态,强制让线程恢复到运行状态
* 然后改变操作标记让线程结束
* */
try{
while(!Thread.currentThread().isInterrupted()){
System.out.println("_____________—————————_________");
Thread.sleep(5000);
}
System.out.println("结束");
}catch(Exception e){
System.out.println("中断结束");
System.out.println(e.getMessage());
}
}
}
public class StopThread {
public static void main(String[] args) throws InterruptedException {
ThreadDemo06 rt = new ThreadDemo06();
Thread t = new Thread(rt);
t.start();
Thread.sleep(2_000);
t.interrupt();
}
这里,当线程为阻塞状态了,确实会停止,但是,如果线程是在运行状态呢,怎么可以让它暴力停止呢?
我们来看网上流传的第三种方式。
class ThreadDemo07{
private Thread executeThread;
private boolean finished = false;
public void execute(final Runnable tt) {
executeThread = new Thread() {
@Override
public void run() {
Thread runner = new Thread(tt);
//设置其为守护线程
runner.setDaemon(true);
runner.start();
try {
//防止被守护线程执行时间短,轮不到守护线程执行任务
runner.join();
//后面还有一句代码,如果守护线程未执行完并且未抛出InterruptedException,是不会执行到下面一句的
finished = true;
} catch (InterruptedException e) {
System.out.println("中断状态改变");
}
}
};
executeThread.start();
}
public void shutdown(long mills) {
long currentTime = System.currentTimeMillis();
//判断守护线程是否被执行完毕
while (!finished) {
//未执行完毕
if ((System.currentTimeMillis() - currentTime) >= mills) {
//超时
System.out.println("任务超时,需要结束他!");
//此时想停止守护线程的任务,给被守护线程抛出InterruptedException,守护线程与被守护线程也都可以
//结束掉
executeThread.interrupt();
break;
}
//未超时
try {
executeThread.sleep(1);
} catch (InterruptedException e) {
System.out.println("执行线程被打断!");
break;
}
}
//执行完毕直接走完被守护线程,守护线程也跟着结束
finished = false;
}
}
public class StopThread {
public static void main(String[] args) throws InterruptedException {
ThreadDemo07 t7 = new ThreadDemo07();
t7.execute(new Runnable() {
@Override
public void run() {
try {
long curr = System.currentTimeMillis();
for(int i = 0;i<50;i++){
while (true){
if ((System.currentTimeMillis() - curr) >= 1_000) {
curr = System.currentTimeMillis();
System.out.println("我在运行!");
break;
}
}
}
//Thread.sleep(2_000);
} catch (Exception e) {
e.printStackTrace();
}
}
});
t7.shutdown(3_000);
}
}
大致的思路是把要执行的代码放在守护线程,用一个线程去控制守护线程的终结和开启,这样当被守护线程停止时,守护线程自然也会被结束掉。在shutdown()时调用interrupt,此时被守护线程出于wait状态,会被捕获到异常从而结束该线程生命周期。此时守护线程也就跟着结束掉了。