bfchengnuo / MyRecord

平时充电做的笔记,一个程序猿的自我修养.
https://bfchengnuo.com/MyRecord/
33 stars 8 forks source link

线程中的中断(interrupt) #34

Closed bfchengnuo closed 5 years ago

bfchengnuo commented 5 years ago

一个线程在未正常结束之前,被强制终止是很危险的事情,因为它可能带来完全预料不到的严重后果;

比如会带着自己所持有的锁而永远的休眠,迟迟不归还锁等。

所以你看到 Thread.suspend()Thread.stop() 等方法都被标记为 Deprecated 了。

那么不能直接把一个线程弄死, 但有时候又有必要让一个线程死掉,或者让它结束某种等待的状态 该怎么办呢?

一个比较优雅而安全的做法是:使用等待/通知机制或者给那个线程一个中断信号, 让它自己决定该怎么办。

中断线程的使用场景:

在某个子线程中为了等待一些特定条件的到来,你调用了 Thread.sleep(10000),预期线程睡 10 秒之后自己醒来,但是如果这个特定条件提前到来的话,来通知一个处于 Sleep 的线程。

又比如说,线程通过调用子线程的 join 方法阻塞自己以等待子线程结束,但是子线程运行过程中发现自己没办法在短时间内结束,于是它需要想办法告诉主线程别等我了,这些情况下就需要中断.

中断是通过调用 Thread.interrupt() 方法来做的; 这个方法通过修改了被调用线程的中断状态来告知线程说它被中断了。

对于非阻塞中的线程,只是改变了中断状态;即 Thread.isInterrupted() 将返回 true;

对于可取消的阻塞状态中的线程,比如等待在这些函数上的线程: Thread.sleep()Object.wait()Thread.join() 线程收到中断信号后会抛出 InterruptedException,同时会把中断状态置回为 true,但调用 Thread.interrupted() 会对中断状态进行复位。

// Interrupted 的经典使用代码
public void run(){
    try{
        // ....
        while(!Thread.currentThread().isInterrupted() && more work to do){
            // do more work;
        }
    } catch(InterruptedException e){
        // thread was interrupted during sleep or wait
    } finally{
        // cleanup, if required
    }
}

不是所有的阻塞方法收到中断后都可以取消阻塞状态,输入和输出流类会阻塞等待 I/O 完成,但是它们不抛出 InterruptedException,而且在被中断的情况下也不会退出阻塞状态. 尝试获取一个内部锁的操作(进入一个 synchronized 块)是不能被中断的,但是 ReentrantLock 支持可中断的获取模式即 tryLock(long time, TimeUnit unit)

https://blog.csdn.net/canot/article/details/51087772

bfchengnuo commented 5 years ago

线程中断最常用的三个方法:interrupt、interrupted 、isInterrupted

interrupted 和 isInterrupted 这两个方法最终都会调用同一个方法,只不过参数一个是 true,一个是 false;这个参数代表是否要清除状态位。