停止一个线程意味着在任务处理完任务之前停掉正在做的操作,也就是放弃当前的操作。停止一个线程可以用Thread.stop() 方法。
使用 stop 方法中止线程
public class ThreadTest{
static class Thread1 extends Thread {
@Override
public void run() {
for (int i = 0; i < 500000; i++) {
System.out.println("打印的数字"+i);
}
}
}
public static void main(String[] args) throws InterruptedException {
Thread1 thread1 = new Thread1();
thread1.start();
//保证子线程进入运行状态,避免还没运行就被终止
Thread.sleep(100);
//暴力停止子线程
thread1.stop();
}
}
输出结果如下:
可以看得出,线程确实被终止了。但最好不要用它。虽然它确实可以停止一个正在运行的线程,但是这个方法是不安全的,而且是已被废弃的方法。
这里面的解释就是:
Stop 方法时被废弃掉的方法,不推荐使用,使用 Stop 方法,会一直向上传播 ThreadDeath 异常,从而使得目标线程解锁所有锁住的监视器,即释放掉所有的对象锁。使得之前被锁住的对象得不到同步的处理,因此可能会造成数据不一致的问题。注释中建议我们取代 Stop 方法,可以增加一个变量。目标线程周期性地检查这个变量。如果变量在某个时间指示线程终止,则目标线程将以有序的方式从 run 方法中返回。当然,如果目标线程长时间进行等待,则可以使用中断的方式来终止线程。
使用退出标志终止线程
通过指定一个条件变量,线程可以控制该变量,内部线程在内部循环检查该变量。
public class ThreadTest extends Thread {
public volatile boolean exit = false;
public void run() {
while (!exit);
}
public static void main(String[] args) throws InterruptedException {
ThreadTest thread = new ThreadTest();
thread.start();
Thread.sleep(5000); // 主线程延迟5秒
thread.exit = true; // 终止线程thread
thread.join();
System.out.println("线程退出!");
}
}
在上面代码中定义了一个退出标志 exit,当 exit 为 true 时,while 循环退出,exit 的默认值为 false,在定义 exit 时,使用了 Java 关键字 volatile,这个关键字可以是 exit 同步,也就是说在同一时刻只能由一个线程来修改 exit 的值, 可以参考我的另外一篇文章: volatile底层实现原理详解
使用 interrupt 方法终止线程
public class ThreadTest extends Thread {
private boolean flag = true;
@Override
public void run() {
while (flag) {
synchronized (this) {
try {
sleep(10000);
} catch (InterruptedException e) {
e.printStackTrace();
this.stopThread();
}
}
}
}
public void stopThread() {
System.out.println("线程已经退出。。。");
this.flag = false;
}
public static void main(String[] args) throws InterruptedException {
ThreadTest threadTest = new ThreadTest();
threadTest.start();
System.out.println("线程开始");
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
threadTest.interrupt();
}
}
interrupt 方法用来设置线程的中断状态,如果目标线程正阻塞于 wait、sleep 等方法时,首先会清除目前线程的中断状态,然后抛出 java.lang.InterruptedException异常
使用 Thread.isInterrupted() 终止线程
public class ThreadTest extends Thread {
int count=0;
public void run(){
System.out.println(getName()+"将要运行...");
while(!this.isInterrupted()){
System.out.println(getName()+"运行中"+count++);
try{
Thread.sleep(400);
}catch(InterruptedException e){
System.out.println(getName()+"从阻塞中退出...");
System.out.println("this.isInterrupted()="+this.isInterrupted());
}
}
System.out.println(getName()+"已经终止!");
}
public static void main(String[] args) throws InterruptedException {
ThreadTest ta=new ThreadTest();
ta.setName("ThreadA");
ta.start();
Thread.sleep(2000);
System.out.println(ta.getName()+"正在被中断...");
ta.interrupt();
System.out.println("ta.isInterrupted()="+ta.isInterrupted());
}
}
什么情况,打断了为什么还能继续输出?
上面已经说过:interrupt 方法用来设置线程的中断状态,如果目标线程正阻塞于 wait、sleep 等方法时,首先会清除目前线程的中断状态,然后抛出 java.lang.InterruptedException异常
目标线程正在进行第 4 次循环,进入了 sleep 操作中,此时收到了主线程的 interrupt 操作,目标线程拥有了中断状态,则先清除中断状态,然后抛出异常,若是 catch 语句没有处理异常,则下一 次循环中 isInterrupted() 为false,线程会继续执行,可能 N 次抛出异常,也没法让线程中止。
那怎么停止当前线程呢?在线程同步的时候要有一个叫 二次惰性检测,能在提升效率的基础上又确保线程真正中同步控制中。那么把线程正确退出的方法称为 “双重安全退出”,不是以 isInterrupted () 为循环条件。而以一个标记做为循环条件。
public class ThreadTest extends Thread {
private boolean isInterrupted=false;
int count=0;
public void interrupt(){
isInterrupted = true;
super.interrupt();
}
public void run(){
System.out.println(getName()+"将要运行...");
while(!isInterrupted){
System.out.println(getName()+"运行中"+count++);
try{
Thread.sleep(400);
}catch(InterruptedException e){
System.out.println(getName()+"从阻塞中退出...");
System.out.println("this.isInterrupted()="+this.isInterrupted());
}
}
System.out.println(getName()+"已经终止!");
}
public static void main(String[] args) throws InterruptedException {
ThreadTest ta=new ThreadTest();
ta.setName("ThreadA");
ta.start();
Thread.sleep(2000);
System.out.println(ta.getName()+"正在被中断...");
ta.interrupt();
System.out.println("ta.isInterrupted()="+ta.isInterrupted());
}
}
执行结果如下: