- 【Java】多线程(2)终止线程
- 1. stop()方法
- 2. 利用线程标志位终止线程
- 3. 利用interrupt()中断线程
在JAVA中有三种方式去停止线程:
- 暴力停止,利用stop()方法,但已被废弃,官方不建议使用。
- 利用线程标志位终止线程。
- 利用interrupt方法来请求终止线程。
为什么弃用stop:
- 调用 stop() 方法会立刻停止 run() 方法中剩余的全部工作,包括在 catch 或 finally 语句中的,并抛出ThreadDeath异常(通常情况下此异常不需要显示的捕获),因此可能会导致一些清理性的工作的得不到完成,如文件,数据库等的关闭。
- 调用 stop() 方法会立即释放该线程所持有的所有的锁,导致数据得不到同步,出现数据不一致的问题。
例如:Thread1被停止stop()后,立即释放内存锁;Thread3获得内存锁,马上加锁。Thread1根本没有清理内存的机会,原来写数据写到一半,现在没有机会继续写了,因为线程被杀掉了;接着,Thread3获得了时间片,开始读数据时发现内存状态异常,读到一个莫名其妙的数据,因为Thread1还没清理干净就停止线程了,留下一个烂摊子给Thread3,Thread3也会面临crash。所以,这样的停止操作是非常危险的。也正是这个原因,无论什么语言都把停止的api废弃了。
2. 利用线程标志位终止线程1、建议线程正常停止—>利用次数,不建议死循环
2、建议使用标志位—>设置一个标志位
3、不要使用stop和destroy等过时或者jdk不建议使用的方法
public class TestStop implements Runnable{
//1、设置一个标志位
private boolean flag =true;
@Override
public void run() {
int i = 0;
while (flag){
System.out.println("run Thread"+i++);
}
}
//2、设置一个公开的方法停止
public void stop(){
this.flag = false;
}
public static void main(String[] args) {
Thread testThread = new Thread(new TestStop(),"InterruptionInJava");
//TestStop testStop = new TestStop();
//new Thread(testStop).start();
for (int i = 0; i < 100; i++) {
if (i==66){
//调用stop方法返回标志位,让线程停止
testThread.stop();
System.out.println("线程该停止啦");
}
System.out.println("main"+i);
}
}
}
3. 利用interrupt()中断线程
当对一个线程调用interrupt方法时,就会设置线程的中断状态。这是每个线程都有的boolean标志。每个线程都应该不时地检查这个标志,以判断线程是否被中断。
public class InterruptionInJava implements Runnable{
private volatile static boolean on = false;
public static void main(String[] args) throws InterruptedException {
Thread testThread = new Thread(new InterruptionInJava(),"InterruptionInJava");
//start thread
testThread.start();
Thread.sleep(1000);
InterruptionInJava.on = true;
testThread.interrupt();
System.out.println("main end");
}
@Override
public void run() {
while(!on){
try {
Thread.sleep(10000000);
} catch (InterruptedException e) {
System.out.println("caught exception right now: "+e);
}
}
}
}
输出:
main end caught exception right now: java.lang.InterruptedException: sleep interrupted
从上面可以看出来,确实被中断了,但是看不出中断的过程。
这就需要调用另外两个与线程有关的中断方法:
public boolean Thread.isInterrupted() //判断是否被中断 public static boolean Thread.interrupted() //判断是否被中断,并清除当前中断状态
这两个方法使得当前线程能够感知到是否被中断了(通过检查标志位)。
package com.state;
public class InterruptTest implements Runnable{
public static void main(String[] args) throws InterruptedException {
Thread testThread = new Thread(new InterruptTest());
//start thread
testThread.start();
Thread.sleep(1000);
testThread.interrupt();
System.out.println("main end");
}
@Override
public void run() {
for (int i = 0; i < 1000000; i++) {
try {
Thread.sleep(1);
} catch (InterruptedException e) {
System.out.println("caught exception right now: "+e);
}
if(Thread.currentThread().isInterrupted()){
break;
}
System.out.println("运行到第"+i+"次");
}
System.out.println("中断执行完成");
}
}
这个结果跑完要很久,可以把这段语句删除:
try {
Thread.sleep(1);
} catch (InterruptedException e) {
System.out.println("caught exception right now: "+e);
}
分别跑一下试一试。
结果是在抛出异常过了很久,程序才停止。
从这个例子可以看出,interrupt()与标志位法很相似但,而且有时并不会立即执行程序。
只有在遇到 sleep() 或者 wait() 这样的操作,用到Interrupt()中断方法比较好。
附一个大佬对停止线程的面试题链接:https://zhuanlan.zhihu.com/p/368149930



