源码解析-Java线程中断源码理解

java线程的中断,不同于操作系统层面的中断,不是立刻将线程的行动中止,而是设置一种标识位,然后被其他调用方判断并进行处理

 

线程中断相关操作,在Thread类中操作   线程的中断位默认为false

 

interrupt();   //设置一个线程的中断位为true

static interrupted();   //调用isInterrupted(),返回当前线程中断位,并重新设置中断位为true

isInterrupted();    //返回当前线程中断位,并重新设置中断位为false

native isTnterrupted(boolean clearInterrupted);    //传入是否需要重置中断位为false;并返回当前线程中断位

中断一个线程,就是设置该线程的中断位为true,具体怎么处理由客户端自己处理

 

中断的具体用途,例如

来自 Object 类的 wait()、wait(long)、wait(long, int),

来自 Thread 类的 join()、join(long)、join(long, int)、sleep(long)、sleep(long, int)

都会抛出throws InterruptedException, 如果线程A调用这些方法后处于阻塞状态,被线程B中断线程A的阻塞状态,会抛出InterruptedException异常 并且设置中断位false

例如Selector的select方法,轮询过程中一旦被中断方法就会返回。

 

如果线程阻塞在 LockSupport.park(Object obj) 方法,也叫挂起,这个时候的中断也会导致线程唤醒,但是唤醒后不会重置中断状态,所以唤醒后去检测中断状态将是 true。

 

总之,中断一般应用在一些长时间阻塞的场景——阻塞方法,这种方法一般都会抛出InterruptedException,往往依赖于外部条件来结束阻塞

 

中断的处理

try {
    Thread.sleep(10000);
} catch (InterruptedException e) {
    // ignore  当外部条件中断了睡眠,抛出InterruptedException异常,被我们捕获后在此处理
}
// go on 

 

AQS对中断的两种处理方法:

 

 两种上锁方式lock() 抢锁过程中被中断,不会处理 继续抢锁

lockInterruptibly()  如果抢锁等待过程中被中断,则抛出异常

 

1. lock()里的

 acquire()方法,

 

acquireQueued()  在这里

 

正常执行到这里parkAndCheckInterrupt(),会使线程park()挂起,然后等待阻塞队列的上一个节点释放锁 通过unpark() 将其唤醒

 如果挂起中途被外部中断,则设置中断位interrupted为true,然后循环再次抢锁,抢锁成功返回中断位,抢锁失败就继续挂起.

 

 2.  lockInterruptiby() 等待过程中如果被中断则抛异常

 

上来就判断,如果被中断就直接抛

 

 

 重点来了, 相比于acquire()方法的等待被中断处理,在这如果等待过程中被中断了就直接抛异常!(之前那个方法是设置个中断位然后继续循环,最后这个中断位能返回获得)

 

在并发包中,有非常多的这种处理中断的例子,提供两个方法,分别为响应中断和不响应中断,对于不响应中断的方法,记录中断而不是丢失这个信息。如 Condition 中的两个方法就是这样的:

 

 通常,如果方法会抛出 InterruptedException 异常,往往方法体的第一句就是

 

posted @ 2020-10-23 15:29  六小扛把子  阅读(140)  评论(0编辑  收藏  举报