Java中终止线程的4种方式

在Java中一个线程终止有以下几种情况和方法

1、线程执行完任务正常结束


2、使用退出标志退出线程(推荐)

一般 run()方法执行完,线程就会正常结束,然而,常常有些线程是伺服线程。它们需要长时间的
运行,只有在外部某些条件满足的情况下,才能关闭这些线程。使用一个变量来控制循环,例如:
最直接的方法就是设一个boolean 类型的标志,并通过设置这个标志为 true或 false 来控制 while
循环是否退出,代码示例:

package top.easyblog;

public class StopThreadByFlag {


    public static void main(String[] args) {
        new Thread(new Task(), "worker1").start();
        new Thread(new Task(), "worker2").start();
        new Thread(new Task(), "worker3").start();
        new Thread(new Task(), "worker4").start();

    }

    static class Task implements Runnable {

        private volatile static boolean exit = false;
        private static int sum = 0;
        private final static Object object = new Object();

        /**
         * 数数任务:4个线程轮流从1数到100
         */
        public void run() {
            while (!exit) {
                synchronized (object) {
                    if (sum > 100) {
                        exit = true;
                    }
                    sum += 1;
                    //让当前线程“休息”一下
                    try {
                        Thread.sleep(1000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    System.out.println(Thread.currentThread().getName() + "==>" + sum);
                }
            }
        }
    }
}

上面的代码中被volatile修饰的exit变量是实现通过标志控制线程退出的关键。它保证了该变量在不同线程之间的可见性,即:一个线程修改了exit的值之后对于其他线程所示可以感知到的,至于他的底层原理请参考volatile关键字底层原理剖析

3、使用interrupt()安全的终止程序(推荐)

关于使用interruput()方法来终止线程,最佳的说明文档就是javadoc了。在这个方法的javadoc上说明了在使用interruput()的三种情况:

  • (1)如果当前线程处于阻塞状态:比如调用了sleep()、wait()以及重载方法、join()以及重载方法或者其他操作让当前线程进入到阻塞状态,此时调用interrupt(),那么它的“中断状态”会被清除为false并且会收到一个InterruptedException异常

    比如一个线程调用了wait()方法后处于阻塞状态,调用interrupt()后会立即将线程的中断标记设为“true”,但是由于线程处于阻塞状态,所以该“中断标记”会立即被清除为“false”,同时,会产生一个InterruptedException的异常。

  • (2)如果线程被阻塞在一个Selector选择器中,那么通过interrupt()中断它时,线程的中断标记会被设置为true,并且它会立即从选择操作中返回。
  • (3)线程未处于阻塞状态,那么通过interrupt()中断线程时,它的中断标记会被设置为“true”

代码示例:

package top.easyblog;

/**
 * @author :huangxin
 * @modified :
 * @since :2020/04/01 16:32
 */
public class StopThreadByInterrupt {


    public static void main(String[] args) {
        new Thread(new Task(),"worker").start();
    }


    static class Task implements Runnable {


        private static int sum = 0;

        /**
         * 数数任务:从1数到100
         */
        public void run() {
            while (true) {
                Thread currentThread = Thread.currentThread();
                if (currentThread.isInterrupted()) {
                    //在这里面可以处理善后的时情,比如关闭网络连接、关闭数据库连接.....
                    System.out.println("处理善后的事情");
                    break;
                }
                sum += 1;
                if (sum >= 100) {
                    //数到100停止
                    currentThread.interrupt();
                }
                //让当前线程“休息”一下
                try {
                    Thread.sleep(500);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                    //由于InterruptedException异常会导致当前线程的终端标志被清除,因此这里必须重新发出中断请求,让中断标志恢复
                    currentThread.interrupt();
                }
                System.out.println(Thread.currentThread().getName() + "==>" + sum);
            }
        }
    }
}

4、使用Java API—stop()终止线程(线程不安全:容易造成子线程释放所持有的所有锁)

程序中可以直接使用 thread.stop()来强行终止线程,但是 stop()方法是很危险的,就象突然关闭计算机电源,而不是按正常程序关机一样,可能会产生不可预料的结果,不安全主要是:thread.stop()调用之后,创建子线程的线程就会抛出 ThreadDeatherror 的错误,并且会释放子线程所持有的所有锁。一般任何进行加锁的代码块,都是为了保护数据的一致性,如果在调用thread.stop()后导致了该线程所持有的所有锁的突然释放(不可控制),那么被保护数据就有可能呈现不一致性,其他线程在使用这些被破坏的数据时,有可能导致一些很奇怪的应用程序错误。因此,并不推荐使用 stop 方法来终止线程。

留言区

还能输入500个字符