如何让线程结束 => 核心是让其run的方法提前结束 ! => 通过代码来控制 !
方法一: isQuit 来实现控制
首先我们先采用boolean类型的 [isQuit] 来对run进行控制 !
public class ThreadDemo8 {
static boolean isQuit = false;//首先设置为false,后面通过对其改变值来对线程的结束
public static void main(String[] args) {
Thread thread = new Thread(()->{
while (!isQuit){
System.out.println("这是一个中断测试!");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println("线程结束!");
});
thread.start();
try {
Thread.sleep(3000);//运行3秒后线程将运行结束!
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("让线程结束!");
isQuit = true;//改变值控制Thread中的while循环结束,实际也是结束了run方法!
}
}
运行结果
这个过程很好的说明了对线程的有了中断处理!
注意:
如果下方代码中的顺序调换可能就会出现"让线程结束!"与"线程结束!"顺序不确定哪个先出现!
System.out.println("让线程结束!");
isQuit = true;//改变值控制Thread中的while循环结束,实际也是结束了run方法!
原因是:无法确定Thread方法(Thread线程)中的先运行还是main方法(主线程)中的先运行 !‘
问题一:如果把isQuit 作为 main 方法中的局部变量,是否可行 ?
lambda表达式/匿名内部类是可以访问外面的定义的局部变量的!但是局部变量必须要用final来修饰,但是用final后变量是不可变了,但是后面要对该变量进行修改,所以行不通!
为什么Java对变量捕获有final的限制?
变量捕获:本质上就是传参,换句话说就是让lambda表达式在自己的栈帧中创建一个新的isQuit并把外面的isQuit值拷贝过来!
isQuit 是局部变量的时候是属于main方法的栈帧中的,但是Thread lambda 是有自己独立的栈帧的(在另外一个线程中的方法),二个栈帧的生命周期是不一致的!如果这样使用的话main的栈帧可能已经销毁,但是Thread的栈帧还在此时它还想调用isQuit不是就出问题了,Java中为了避免isQuit不同步,就干脆把不让你对该值进行修改,这就是为什么Java对变量捕获有final的限制!
方法二: isInterrupted 来实现控制
刚刚的方法可能不是特别的高大上,接下来我们换一个方法 (通过Thread类中的方法)来解决!
public class ThreadDemo9 {
public static void main(String[] args) {
Thread thread = new Thread(()->{
while (!Thread.currentThread().isInterrupted()){ //代替了!isQuit
//Thread.currentThread()获取当前实例的作用!
System.out.println("这是一个中断测试!");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
break;//为了顺利让线程结束!
}
}
System.out.println("线程结束!");
});
thread.start();
try {
Thread.sleep(3000);//运行3秒后线程将运行结束!
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("让线程结束!");
thread.interrupt();//代替了isQuit = true;
}
}
运行结果
注:想要下面不抛异常,可以删除catch中的 e.printStackTrace()代码即可 !
还是依旧可以对线程进行中断!这个更加的利用了Thread中的方法,更加的精简与高大上!
问题二:Break在代码中的作用分析!
使用break的作用是为了让代码线程可以顺利的结束 !当执行interrupt()之后已经将值改变为true,由于Thread的中的sleep方法可能会被提前唤醒!导致清除了Thread对象的isInterrupted的标志位,值变回了false,导致线程无法结束,这里可以设置break可以强制线程结束!
提前唤醒的原因:就是可能interrupt()方法执行后Thread中的sleep本来应该在1秒被唤醒,结果在0.8秒的时候提前被唤醒了!
sleep被提前唤醒后会进行的操作:1.抛出interruptedException(紧接着就会被catch获取到)
2.清除Thread 对象的isInterrupted的标志位!