java多线程系统 ——(6)interrupt()方法和线程终止方式

1. interrupt()方法介绍

interrupt()方法

interrupt()的作用是中断此线程(此线程不一定是当前线程,而是指调用该方法的Thread实例所代表的线程),只会给线程设置一个中断标志,线程仍会继续运行

本线程中断自己是被允许的;其它线程调用本线程的interrupt()方法时,会通过checkAccess()检查权限。这有可能抛出SecurityException异常。

如果本线程是处于阻塞状态:调用线程的wait(),、join()、sleep()方法会让它进入阻塞状态。若线程在阻塞状态时,调用了它的interrupt()方法,那么它的“中断状态”会被清除并且会收到一个InterruptedException异常。例如,线程通过wait()进入阻塞状态,此时通过interrupt()中断该线程;调用interrupt()会立即将线程的中断标记设为“true”,但是由于线程处于阻塞状态,所以该“中
断标记”会立即被清除为“false”
,同时,会产生一个InterruptedException的异常。

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

interrupted()方法

作用是测试当前线程 是否被中断(检查中断标志),返回一个boolean并清除中断状态,第二次再调用时中断状态已经被清除,将返回一个false。

isInterrupted()方法

作用是测试此线程 是否被中断(检查中断标志),返回一个boolean,不清除中断状态

2. interrupt示例

上面的介绍中有说,interrupt只能设置一个中断标记,并不能实际中断线程的运行。下面通过一个例子来说明这一点:

public class InterruptTest extends Thread {

    public void run(){
        for (int i = 0 ; i < 5; i++){
            try {
                sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("愉快的玩耍" + i);
        }
    }

    public static void main(String[] args){
        InterruptTest test = new InterruptTest();
        test.start();
        test.interrupt();
        System.out.println("线程是否被中断:"+ test.isInterrupted());
        System.out.println("线程是否存活:" + test.isAlive());
    }

}

运行结果如下:
在这里插入图片描述

从运行结果我们可以看出,线程在sleep()中被中断,中断标记被设置为true,并且抛出了InterruptedException异常,但是该线程依然在运行。因此interrupt()方法只会设置中断标志,并不会实际终止线程。

再来看一个例子,把上面的代码稍微做一点改动:

    public static void main(String[] args){
        InterruptTest test = new InterruptTest();
        test.start();
        test.interrupt();
        System.out.println("线程是否被中断:"+ test.isInterrupted());
        System.out.println("线程是否存活:" + test.isAlive());
        System.out.println("调用interrupted():" + test.interrupted());
        System.out.println("调用interrupted():" + test.interrupted());
    }

运行结果:
在这里插入图片描述
前面我们讲过,interrupted()方法不仅可以返回中断标记,还能将中断标记设置为false,那第一次调用的结果为什么不是true呢?这是因为interrupted()方法返回和清除的是当前线程的中断标志,这段代码运行在main()中,那当前线程当然是主线程,所以返回清除的是主线程的中断标记。

3. 如何优雅的终止线程

interrupt()方法只能设置中断标记,那要真正终止线程的运行,需要使用什么方法呢?首先应该明确的是Thread中的stop()和suspend()方法,由于固有的不安全性,已经建议不再使用!

1. 终止阻塞的线程

终止阻塞的线程可以在外部调用interrupt()方法使线程产生interruptedException,在代码内部捕获该异常退出运行,示例如下:

@Override
public void run() {
    try {
        while (true) {
            // 执行任务...
        }
    } catch (InterruptedException ie) {  
        // 由于产生InterruptedException异常,退出while(true)循环,线程终止!
    }
}

如果我们将try/catch放在while循环内部的话,就需要手动添加break来中断,负责while循环不会通知。

2. 终止正在运行的线程

终止正在运行的线程有两种方式,一种是通过判断中断标记,另一个是额外添加标记,这里推荐使用第一种,来看一下示例:

@Override
public void run() {
    while (!isInterrupted()) {
        // 执行任务...
    }
}

综合上面两种线程的状态,我们可以得出通用的终止方式:

@Override
public void run() {
    try {
        // 1. isInterrupted()保证,只要中断标记为true就终止线程。
        while (!isInterrupted()) {
            // 执行任务...
        }
    } catch (InterruptedException ie) {  
        // 2. InterruptedException异常保证,当InterruptedException异常产生时,线程被终止。
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值