并发编程(七)线程如何优雅地终止

一、停止线程的几种方法

  • 使用退出标志,使线程正常退出,也就是当 run() 方法完成后线程中止。
  • 使用interrupt()方法中断线程。
  • 使用stop()方法强行终止线程,但是不推荐使用这个方法,该方法已被弃用!!!

二、方法详解

使用标志位终止线程

/**
 * 设置标识位停止线程
 */
public class MyThreadStop {

    //计数
    private static int count = 0;
    //退出标识符
    public static boolean exit = false;


    /**
     * 核心线程
     */
    public static void main(final String[] arguments) throws InterruptedException {
        Thread t = new Thread(new TestThread());
        t.start();
    }

    /**
     * 同步方法
     */
    public static synchronized void countNum() {
        for (int i = 0; i < 100000; i++) {
            if (count >= 500000) {
                exit = true; //修改标志位,退出线程
            } else {
                count++;
                System.out.println(count);
            }
        }
    }

    /**
     * 线程实体(实现Runnable接口)
     */
    static class TestThread implements Runnable {

        public void run() {
            while (!exit) {//当标识符没设置停止时,一直做参数递增
                countNum();
            }
        }
    }
}

使用interrupt()方法中断线程

  • interrupt() 方法并不像在 for 循环语句中使用 break 语句那样干脆,马上就停止循环。
  • 调用 interrupt() 方法仅仅是在当前线程中打一个停止的标记,并不会立即终止线程。
  • 至于目标线程收到通知后会如何处理,则完全由目标线程自行决定。
/**
 * interrupt()方法停止线程
 */
public class MyThreadStop {

    //计数器
    private static int count = 0;

    /**
     * 核心线程
     */
    public static void main(final String[] arguments) throws InterruptedException {
        Thread t = new Thread(new TestThread());
        t.start();
        //休眠一会儿,然后中断
        t.sleep(200);
        t.interrupt();
    }

    /**
     * 同步方法
     */
    public static synchronized void countNum() {
        for (int i = 0; i < 500000; i++) {
            count++;
            System.out.println(count);
        }
    }

    /**
     * 线程实体(实现Runnable接口)
     */
    static class TestThread implements Runnable {
        public void run() {
            countNum();
        }
    }
}

  上面的例子我们发现,好像interrupt方法并没有马上停止线程,还是继续跑完了,这是由于interrupt() 方法仅仅是在当前线程中打一个停止的标记,并不会立即终止线程。 至于目标线程收到通知后会如何处理,则完全由目标线程自行决定。

  我们可以改造一下~

/**
 * interrupt()方法停止线程
 */
public class MyThreadStop {

    //计数器
    private static int count = 0;

    /**
     * 核心线程
     */
    public static void main(final String[] arguments) throws InterruptedException {
        Thread t = new Thread(new TestThread());
        t.start();
        //休眠一会儿,然后中断
        t.sleep(200);
        t.interrupt();
    }


    /**
     * 线程实体(实现Runnable接口)
     */
    static class TestThread implements Runnable {
        public void run() {
            for (int i = 0; i < 500000; i++) {
                //判断线程是否被通知中断
                if (Thread.currentThread().isInterrupted()) {
                    //处理中断逻辑
                    break;
                }
                count++;
                System.out.println(count);
            }
        }
    }
}

  可以发现,在加入中断判断以后,线程停止了工作

  PS:当线程被 sleep() 休眠时,如果被中断,就会抛出一个 InterruptedException异常。

  PS:Thread.sleep() 方法由于中断而抛出的异常,是会清除中断标记的,线程后面的代码会继续执行

stop()方法

  stop()方法停止线程的方式相当粗暴,直接停止线程工作,相当不安全,虽然现在已经弃用,还是简单的了解一下吧。

  为什么弃用stop:

  • 调用 stop() 方法会立刻停止 run() 方法中剩余的全部工作,包括在 catch 或 finally 语句中的,并抛出ThreadDeath异常(通常情况下此异常不需要显示的捕获),因此可能会导致一些清理性的工作的得不到完成,如文件,数据库等的关闭。
  • 调用 stop() 方法会立即释放该线程所持有的所有的锁,导致数据得不到同步,出现数据不一致的问题。

好文推荐:

猜你喜欢

转载自www.cnblogs.com/riches/p/12023692.html