Java并发编程艺术 - 线程中断

中断可以理解为线程的一个标识位属性,它表示一个运行中的线程是否被其他线程进行了中断操作。中断好比其他线程对该线程打了个招呼,其他线程通过调用该线程的interrupt()
方法对其进行中断操作。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
public static void main(String[] args) {
AtomicInteger atomicInteger = new AtomicInteger(0);

Runnable runnable = () -> {
while (true) {
atomicInteger.incrementAndGet();

try {
//阻塞cpu
Thread.sleep(1000);

if (atomicInteger.get() > 5) {
//中断信号
Thread.currentThread().interrupt();
}

} catch (InterruptedException e) {
e.printStackTrace();
//异常后的中断标记
System.out.println(Thread.currentThread().isInterrupted() + "-" + atomicInteger.get());
}

//输出中断标记
System.out.println(Thread.currentThread().isInterrupted() + "-" + atomicInteger.get());
}
};

Thread thread = new Thread(runnable);
//就绪,并行;不能直接使用run,run是串行
thread.start();
}

输出

1
2
3
4
5
6
7
8
9
10
11
false-1
false-2
false-3
false-4
false-5
true-6
java.lang.InterruptedException: sleep interrupted
at java.lang.Thread.sleep(Native Method)
at ThreadInterrupt.lambda$main$0(ThreadInterrupt.java:19)
at java.lang.Thread.run(Thread.java:748)
false-7

线程通过检查自身是否被中断来进行响应,线程通过方法isInterrupted()来进行判断是否被中断,也可以调用静态方法Thread.interrupted()对当前线程的中断标识位进行复位true-6。如果该线程已经处于终结状态,即使该线程被中断过,在调用该线程对象的isInterrupted()时依旧会返回false。

从上面false-7可以看到,抛出InterruptedException的方法,Java虚拟机会先将该线程的中断标识位清除,然后抛出InterruptedException,此时调用isInterrupted()方法将会返回false。

interrupt有两个非常类似的方法,interrupted 和 islnterrupted。Interrupted 方法是一个静态方法, 它检测当前的线程是否被中断。 而且, 调用 interrupted 方法会清除该线程的中断状态。另一方面,islnterrupted 方法是一个实例方法,可用来检验是否有线程被中断。调用这个方法不会改变中断状态。

1
2
3
4
5
6
7
8
9
void interrupt()
实例方法,针对线程对象。向线程发送中断请求。线程的中断状态将被设置为 true。如果目前该线程被一个sleep调用阻塞,那么,InterruptedException 异常被抛出。
static boolean interrupted()
静态方法,针对当前线程。测试当前线程(即正在执行这一命令的线程)是否被中断。注意,这是一个静态方法。
这一调用会产生副作用—它将当前线程的中断状态重置为 false
boolean islnterrupted()
实例方法,针对线程对象。测试线程是否被终止。不像静态的中断方法,这一调用不改变线程的中断状态。
static Thread currentThread()
返回代表当前执行线程的 Thread 对象。

扩展

当对一个线程调用interrupt方法时,线程的中断状态将被置位。这是每一个线程都具有的 boolean标志。每个线程都应该不时地检査这个标志,以判断线程是否被中断。

要想弄清中断状态是否被置位,首先调用静态的 Thread.currentThread 方法获得当前线
程,然后调用 islnterrupted 方法:

1
2
3
4
while (!Thread.currentThread().islnterrupted() && more work to do)
{
do more work
}

但是,如果线程被阻塞,就无法检测中断状态。这是产生 InterruptedExceptioii 异常的地方。当在一个被阻塞的线程(调用 sleep 或 wait) 上调用 interrupt 方法时,阻塞调用将会被Interrupted Exception 异常中断

中断一个线程不过是引起它的注意。被中断的线程可以决定如何响应中断。某些线程是如此重要以至于应该处理完异常后, 继续执行,而不理会中断。这种线程的 run 方法具有如下形式:

1
2
3
4
5
6
7
8
9
10
11
12
13
Runnable r = () -> {
try{
while (!Thread.currentThread().islnterrupted0 && more work to do){
do more work
Thread,sleep(delay);
}
}catch(InterruptedException e){
// thread was interr叩ted during sleep or wait
}finally{
cleanup, ifrequired
}
// exiting the run method terminates the thread
};

如果在每次工作迭代之后都调用 sleep 方法(或者其他的可中断方法)islnterrupted 检测既没有必要也没有用处。如果在中断状态被置位时调用 sleep 方法,它不会休眠。相反,它将清除这一状态并拋出 IntemiptedException。因此,如果你的循环调用 sleep,不会检测中断状态。

------ 本文结束------

本文标题:Java并发编程艺术 - 线程中断

文章作者:Perkins

发布时间:2019年09月03日

原始链接:https://perkins4j2.github.io/posts/45493/

许可协议: 署名-非商业性使用-禁止演绎 4.0 国际 转载请保留原文链接及作者。