面试官:如何停止一个正在运行的线程

面试官:如何停止一个正在运行的线程

停止一个线程意味着在任务处理完任务之前停掉正在做的操作,也就是放弃当前的操作。停止一个线程可以用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());

}

}

执行结果如下:

相关推荐

WoW 7.0开服时间正式公布!玩家翘首以盼!
bet3365也可以

WoW 7.0开服时间正式公布!玩家翘首以盼!

📅 06-29 👁️ 1484
过感恩节的国家有哪些
bet3365也可以

过感恩节的国家有哪些

📅 07-18 👁️ 2111