如何终止线程?

x33g5p2x  于2021-12-18 转载在 其他  
字(3.6k)|赞(0)|评价(0)|浏览(365)

在 Java 中有三种方法可以使正在运行的线程终止:

  1. 使用退出标志使线程正常退出。
  2. 使用 interrupt() 方法终止线程。
  3. 使用 stop() 方法强行终止线程,这种方法是过期作废的方法,使用它可能会发生不可预料的结果,不推荐使用。

下面我将对这三种方法分别进行举例说明。

一、使用退出标志

在 run() 方法执行完毕后,线程就终止了,但是在某些特殊的情况下,run() 方法会被一直执行,此时就可以通过修改退出标志来结束 run() 方法,代码如下:

public class Run {
    public static void main(String[] args) throws InterruptedException {
        MyThread myThread = new MyThread();
        myThread.start();
        // 200 毫秒后终止线程
        Thread.sleep(200);
        myThread.flag = false;
    }
}

class MyThread extends Thread {
    private int i = 0;

    public volatile boolean flag = true;

    @Override
    public void run() {
        System.out.println("start");
        while (flag) {
            System.out.println("i = " + i++);
        }
        System.out.println("end");
    }
}

二、使用 interrupt() 方法

首先要搞清楚一点,调用 interrupt() 方法仅仅是在当前线程中做了一个终止标记,并不会真正终止线程,如果想要真正终止线程,首先需要获取终止标记,然后根据终止标记的值来判断是否需要终止线程,那么如何获得终止标记的值呢?Java 提供了两个方法,部分源码如下:

public static boolean interrupted();
public boolean isInterrupted();

上述两个方法都可以获取线程终止标记的值,它们之间的区别如下:

  1. interrupted() 方法用来获取当前线程终止标记的值,并且会清除终止标记(这句话的意思是把终止标记置为 false)。
  2. isInterrupted() 方法获取调用该方法的线程的终止标记的值,但不会清除终止标记。

下面我们通过例子来看一下两者的区别,调用 interrupted() 方法的代码如下:

public class Run {
    public static void main(String[] args) {
        System.out.println("当前线程是:" + Thread.currentThread().getName() + ",终止标记为:" + Thread.interrupted());
        Thread.currentThread().interrupt();
        System.out.println("当前线程是:" + Thread.currentThread().getName() + ",终止标记为:" + Thread.interrupted());
        System.out.println("当前线程是:" + Thread.currentThread().getName() + ",终止标记为:" + Thread.interrupted());
    }
}

控制台输出如下:

当前线程是:main,终止标记为:false
当前线程是:main,终止标记为:true
当前线程是:main,终止标记为:false

控制台第一行输出 false 是因为此时还没有调用 interrupt() 方法;第二行输出 true 是因为此时已经调用了 interrupt() 方法,终止标记被置为 true,但因为 interrupted() 方法具有清除功能,在每次调用 interrupted() 方法后终止标记都会被置为 false,所以第三行输出了 false。

调用 isInterrupted() 方法的代码如下:

public class Run {
    public static void main(String[] args) {
        MyThread myThread = new MyThread();
        myThread.start();
        myThread.interrupt();
        System.out.println("线程:" + myThread.getName() + "的终止标记为:" + myThread.isInterrupted());
        System.out.println("线程:" + myThread.getName() + "的终止标记为:" + myThread.isInterrupted());
    }
}

class MyThread extends Thread {
    @Override
    public void run() {
        System.out.println("Hello World!");
    }
}

控制台输出如下:

线程:Thread-0的终止标记为:true
线程:Thread-0的终止标记为:true
Hello World!

因为 isInterrupted() 方法不具备清除终止标记的功能,所以在调用了 interrupt() 方法后,两次输出都为 true。

在学会怎么获取终止标记后,我们就可以通过终止标记的值来判断什么时候终止线程了,下面直接上案例代码:

public class Run {
    public static void main(String[] args) throws InterruptedException {
        MyThread myThread = new MyThread();
        myThread.start();
        Thread.sleep(10);
        myThread.interrupt();
    }
}

class MyThread extends Thread {
    @Override
    public void run() {
        try {
            for (int i = 0; i < 1000; i++) {
                if (this.isInterrupted()) {
                    System.out.println("此时已经是终止状态了,我要退出了!");
                    throw new InterruptedException();
                }
                System.out.println("i = " + (i + 1));
            }
        } catch (InterruptedException e) {
            System.out.println("我已经退出了!");
            e.printStackTrace();
        }
    }
}

控制台输出部分代码如下:

i = 372
i = 373
i = 374
i = 375
i = 376
i = 377
i = 378
此时已经是终止状态了,我要退出了!
我已经退出了!
java.lang.InterruptedException
	at t006.MyThread.run(Run.java:19)

如果 interrupt() 和 sleep() 方法碰到一起会出现什么情况呢?

答:会抛出 java.lang.InterruptedException 异常,无论是先执行 interrupt() 方法还是先执行 sleep() 方法都会抛出异常。

三、使用 stop() 方法

使用 stop() 方法可以强行停止线程,这种方法方法过于暴力,使用时可能造成不可预料的结果,现在已经被废弃,但我们还是需要简单了解一下,下面通过一段代码来初步了解 stop() 方法的使用,代码如下:

public class Run {
    public static void main(String[] args) throws InterruptedException {
        MyThread myThread = new MyThread();
        myThread.start();
        // 让 main 线程等待 8 秒
        Thread.sleep(8000);
        myThread.stop();
    }
}

class MyThread extends Thread {
    private int i = 0;

    @Override
    public void run() {
        try {
            while (true) {
                i++;
                System.out.println("i=" + i);
                Thread.sleep(1000);
            }
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

控制台输出如下:

i=1
i=2
i=3
i=4
i=5
i=6
i=7
i=8

代码逻辑很简单,我就不做解释了。

调用 stop() 方法时会抛出 java.lang.ThreadDeath 异常,但在通常情况下,此异常不需要显示地捕捉。

相关文章