Java多线程编程中,有时候在线程的run方法中,我们使用死循环来处理我们的任务,在不控制的情况下线程会一直执行,无法退出。因此在主线程中需要一些方式控制线程退出。

在Java的多线程编程中有3种方式退出线程:

  1. 使用线程的stop方法(不推荐)。
  2. 使用退出标志位。
  3. 使用Interrupt() 方法退出线程。(推荐)

下面就这三种方法做一些简要的讲解和使用。

使用线程的stop方法(不推荐)

使用该方法就像运行中的计算机突然停电,它是不安全的,而且该方法已被弃用,最好不要使用它。

线程的stop方法会抛出一个ThreadDeatherror的错误,并且会释放子线程所持有的所有锁,这样会导致数据的不一致性。

例子:

class ThreadTask extends Thread{
    @Override
    public void run() {
        while(true){
            System.out.println(this.getName() + "run task ");
        }
    }
}

public class ThreadStopExample extends Thread {

    public static void main(String args[]) throws InterruptedException {
        ThreadTask task1 = new ThreadTask();

        task1.start();
        Thread.sleep(100);
        task1.stop();
    }

} 

我们在Idea中stop()代码行也是一个删除线,说明该方法是弃用的。

Java中退出线程的几种方法

使用退出标志位。

使用该方法的方式是在线程类中定义一个标志位如:isExist,通过该标志位判断循环是否继续执行。

class ThreadTask extends Thread{
    private volatile Boolean isExit = false;

    public void setIsExit(Boolean isExit) {
        this.isExit = isExit;
    }

    @Override
    public void run() {
        while(!isExit){
            //处理一些任务
            System.out.println(this.getName() + "run task ");
        }
    }
}

public class ThreadStopFlagExample extends Thread {

    public static void main(String args[]) throws InterruptedException {
        ThreadTask task1 = new ThreadTask();

        task1.start();
        Thread.sleep(1);

        //设置退出标志
        task1.setIsExit(true);
    }

} 

测试一下

在上面的例子中,我们sleep(1)后,修改子线程的标志位isExit让线程退出。

使用Interrupt() 方法退出线程。(推荐)

interrupt() 方法是中断线程,它是通知目标线程退出,并不是立即退出,也就是说,线程内部也得用某个方法( Thread.isInterrupted() )断是否需要退出,当然你可以拒绝。

例子:

class ThreadTask extends Thread{

    @Override
    public void run() {
        while(true){
            //判断是否发送了中断
            if (Thread.currentThread().isInterrupted()) {
                break;
            }
            System.out.println(this.getName() + "run task ");
        }
    }
}

public class ThreadStopInterruptExample extends Thread {

    public static void main(String args[]) throws InterruptedException {
        ThreadTask task1 = new ThreadTask();

        task1.start();
        Thread.sleep(10);

        //发送中断信号
        task1.interrupt();
    }

} 

测试一下

上面的代码中我们通过Thread.currentThread().isInterrupted()方法判断是否需要退出,它和标志位有点类似。

我们再看一个在线程内部 while循环中使用sleep方法的例子:

class ThreadTask extends Thread{

    @Override
    public void run() {
        while(true){
            //判断是否发送了中断
            if (Thread.currentThread().isInterrupted()) {
                break;
            }
            try {
                Thread.sleep(1000);//内部使用了sleep方法
            } catch (InterruptedException e) {
                e.printStackTrace();
            }

            System.out.println(this.getName() + "run task ");

        }
    }
}

public class ThreadStopInterruptSleepExample extends Thread {

    public static void main(String args[]) throws InterruptedException {
        ThreadTask task1 = new ThreadTask();

        task1.start();
        Thread.sleep(100);

        //发送中断信号
        task1.interrupt();
    }

}
运行该程序,会报 java.lang.InterruptedException: sleep interrupted 异常,并且线程会一直运行下去。

Java中退出线程的几种方法

所以这个时候需要将上述在sleep catch代码块中退出线程即可,修改后的代码如下:

try {
    Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
    break;//捕获到异常,跳出循环
}