Android并发:Java线程中断(interrupt、isInterrupted和interrupted)

最近在做一些并发任务使用线程池的时候,发现当我们需要退出任务关闭线程池时,有 shutdown() 与 shutdownNow() 两个方法。这里对这两个方法不做过多的深入研究,它们的不同点就是:shutdown() 只会结束线程池中未执行的任务,shutdownNow() 则直接结束全部任务,而它们结束任务的原理本质都是一致的,就是通过遍历线程池中的线程,然后逐个调用 Thread.interrupt() 来进行中断。

这时问题就来了,何为线程的中断呢?我查阅了一下Java Thread的API,发现有关方法有三个 interrupt、isInterrupted和interrupted,那么它们的作用、原理和区别又分别是什么呢?我们这里就深入浅出的来聊一聊 Java 线程的中断吧~


interrupt

public void interrupt()

Interrupts this thread.

Unless the current thread is interrupting itself, which is always permitted, the checkAccess method of this thread is invoked, which may cause a SecurityException to be thrown.

If this thread is blocked in an invocation of the wait()wait(long), or wait(long, int) methods of the Object class, or of the join()join(long)join(long, int)sleep(long), or sleep(long, int), methods of this class, then its interrupt status will be cleared and it will receive an InterruptedException.

If this thread is blocked in an I/O operation upon an interruptible channel then the channel will be closed, the thread's interrupt status will be set, and the thread will receive a ClosedByInterruptException.

If this thread is blocked in a Selector then the thread's interrupt status will be set and it will return immediately from the selection operation, possibly with a non-zero value, just as if the selector's wakeup method were invoked.

If none of the previous conditions hold then this thread's interrupt status will be set.

Interrupting a thread that is not alive need not have any effect.

Throws:

SecurityException - if the current thread cannot modify this thread

这是官方文档中对其的介绍,大致意思就是:

当前线程中断自身是总被允许的,若是其它线程调用当前线程的interrupt()方法时,会通过调用checkAccess()方法来检查权限,这有可能抛出SecurityException异常。
如果当前线程在调用此线程的wait(), wait(long)或wait(long, int)会让它进入等待(阻塞)状态,或者调用join(), join(long), join(long, int), sleep(long), sleep(long, int)也会让它进入阻塞状态。那么当线程在阻塞状态时,调用了它的interrupt()方法,它的“中断状态”便会被清除为默认的“false”,并且会收到一个InterruptedException异常。
如果以上条件都不成立,那么通过interrupt()中断线程时,它的中断标记会被设置为“true”。
若线程已经终止,则调用该方法不会产生任何操作。

首先,我们需要了解什么时候线程需要中断:

在我的理解中,一个线程在未正常结束之前,被强制终止是很危险的事情,这就是为何 Thread.stop() 和 Thread.suspend() 都被Deprecated 了。那么需要中断的情况我归纳为2种:

1.当某个线程在做一个无限循环的操作,同时​该循环的其中一个决定因素就是需要不断检查自身的中断状态;

2.某个线程为了等待一个特定条件的到来阻塞了自己,但此时我们发现该特定条件无法到来或者提前到来、发生了变故等,就需要想办法告诉此阻塞中的线程。

我们再回到 interrupt() 这个方法,该方法实质上并非是能直接强制中断线程,它起的作用仅仅是改变调用线程的中断状态(分为处于阻塞状态和非阻塞状态两种情况),即通过isInterrupted() 方法来获取到的 boolean值,是否起作用要具体看该线程的代码是如何编写的。(中断状态默认为false)

这里总结一下:调用interrupt()方法,如果该线程处于非阻塞状态,则会立即改变线程的中断状态为true;若该线程处于阻塞状态,则该线程的中断状态也会立即设为true,但由于处于阻塞状态,则中断状态又会立刻被清除掉,变为false,同时会抛出一个InterruptedException的异常。我们就能通过这个中断状态和抛出的InterruptedException异常来做出相应的操作。

这么说大家也许还不是很明白,咱们还是用代码说话吧= =,接下来举三个简单的例子:

1.处于“非阻塞状态”的线程,但是通过改变中断状态并不能中断线程。 

@Override
public void run() {
    while (true) {
        try {
            // 执行任务...
            // 循环逻辑与中断状态毫无关系,则interrupt()方法不会带来任何改变
        } catch (InterruptedException ie) {  

            break;
        }
    }
}

2.处于“非阻塞状态”的线程,通过改变中断状态可以中断线程。

@Override
public void run() {
    while (!isInterrupted()) {
        try {
            // 执行任务...
            // 调用线程的interrupt()方法,使用线程的中断标记为true,即isInterrupted()会返回true。此时,就会退出while循环而中断线程。
        } catch (InterruptedException ie) {  

            break;
        }
    }
}

3.处于“阻塞状态”的线程

@Override
public void run() {
    try {
        while (true) {
            // 执行任务...
        }
    } catch (InterruptedException e) {  
        // 由于处于阻塞状态,则会产生InterruptedException异常,退出while(true)循环,但并非意味着线程终止,while()循环后的任务则会继续执行
    }
    // 执行其它任务...
}

interrupted() 和 isInterrupted()

最后我们来谈谈 interrupted() 和 isInterrupted(),这两个方法的作用很简单,看名字也能明白,就是能够用于检测该线程的“中断标记”。

public boolean isInterrupted();

public static boolean interrupted() { return currentThread().isInterrupted(true); }

可以看到,interrupted 是作用于当前线程,isInterrupted 则是作用于调用该方法的线程对象所对应的线程。两者的区别在于interrupted()在返回中断标记之后,它还会清除该线程的中断标记(即将中断标记设为false),而isInterrupted()仅仅是返回中断标记。因此,Thread.interrupted() 第二次调用,会永远返回false。

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值