返回信息流Interrupt是什么意思?
Java里,每个线程都有一个“interrupted”标志。如果调用这个线程的interrupt()方法,就会设置这个标志。这个标记的意思是建议该线程停止。
可以使用Thread.interrupted()静态方法检测当前线程是否被中断。如果检测到true,那么同时会清除当前线程的interrupt标记。
Java不推荐使用Thread.stop()来终止线程。推荐的做法是,时不时地检测interrupt()状态,并在尽可能短的时间内自行终止。
下面的程序每计算若干个数,就检测是否被中断。如果被中断了,返回部分结果。
package cn.byr.nuanyangyang.interr;
class InterruptibleSumCalculator implements Runnable {
private long low;
private long high;
private boolean finished = false;
private long result = 0;
public InterruptibleSumCalculator(long low, long high) {
this.low = low;
this.high = high;
}
@Override
public void run() {
final long CHUNK_SIZE = 1024;
long s = 0;
for (long i = low; i <= high; i += CHUNK_SIZE) {
for (long j = i; j < i + CHUNK_SIZE; j++) {
s += j;
}
if (Thread.interrupted()) {
System.out.format("Sum calculation interrupted.\nCurrent i: %d, partial sum: %d\n", i, s);
result = s;
Thread.currentThread().interrupt(); // re-set the interrupted flag.
// Maybe this calculator is part of a bigger job.
// I'll come back to this issue later.
return;
}
}
finished = true;
result = s;
}
public boolean isFinished() {
return finished;
}
public long getResult() {
return result;
}
}
public class InterruptibleSum {
public static void main(String[] args) throws InterruptedException {
InterruptibleSumCalculator isc = new InterruptibleSumCalculator(0L, 100000000000L);
Thread t = new Thread(isc);
System.out.println("Start calculating...");
t.start();
System.out.println("Waiting for it to finish...");
t.join(1000);
if(t.isAlive()) {
System.out.println("Still alive. Try to interrupt it...");
t.interrupt();
System.out.println("Waiting for it to die...");
t.join();
} else {
System.out.println("Already dead.");
}
System.out.format("Finished? %s\nResult: %d\n", isc.isFinished(), isc.getResult());
}
}
很多标准库中的函数都会响应interrupt()函数。在被中断的时候,会抛出InterruptedException。
比如,Thread.sleep()。
package cn.byr.nuanyangyang.interr;
public class InterruptibleSleep {
public static void main(String[] args) throws InterruptedException {
Thread sleeper = new Thread(() -> {
try {
Thread.sleep(1000);
System.out.println("I woke up by myself.");
} catch (InterruptedException e) {
System.out.println("I was interrupted.");
// Thread.currentThread().interrupt();
// I know it is the whole job, so no need to re-set the flag.
}
});
sleeper.start();
Thread.sleep(500);
System.out.println("Main thread woke up.");
sleeper.interrupt();
sleeper.join();
}
}
interrupt的意思是建议线程停止。所以,正确的处理方法是停止当前的作业。
一个典型的错误是直接将会抛出InterruptException的语句用try-catch括起来,这样编译可以通过,但却是错误的处理方法。比如下面这个程序:
package cn.byr.nuanyangyang.interr;
public class CounterWrong {
public static void main(String[] args) throws InterruptedException {
Thread counter = new Thread(() -> {
int i = 0;
while (true) {
System.out.println(i);
i++;
try {
Thread.sleep(1000);
} catch (InterruptedException e) { // WRONG!!!
e.printStackTrace();
}
}
});
counter.start();
Thread.sleep(3500);
counter.interrupt();
counter.join();
}
}
这样的程序根本终止不了,因为一interrupt,sleep就会抛出InterruptedException,同时还会清除interrupt标记。所以,程序运行的现象就是程序在3.5秒的时刻打印了一个异常,然后计数器继续工作。
0
1
2
3
java.lang.InterruptedException: sleep interrupted
4
at java.lang.Thread.sleep(Native Method)
at cn.byr.nuanyangyang.interr.CounterWrong.lambda$0(CounterWrong.java:11)
at cn.byr.nuanyangyang.interr.CounterWrong$$Lambda$1/2003749087.run(Unknown Source)
at java.lang.Thread.run(Thread.java:745)
5
6
正确的做法是停止运行
package cn.byr.nuanyangyang.interr;
public class CounterRight {
public static void main(String[] args) throws InterruptedException {
Thread counter = new Thread(() -> {
int i = 0;
try {
while (true) {
System.out.println(i);
i++;
Thread.sleep(1000);
}
} catch (InterruptedException e) {
System.out.println("Counter interrupted. Stop.");
// Thread.currentThread().interrupt();
// I know it is the whole job, so no need to re-set the flag.
}
});
counter.start();
Thread.sleep(3500);
counter.interrupt();
counter.join();
}
}
有时候,你做的是一个函数,而不是一个完整的Thread或者Runnable。这种情况,可以让函数抛出InterruptedException,而不是在函数内部处理。这等于把处理InterruptedException的责任抛给了调用者。以原来的计算器为例,如果是一个函数而不是Runnable,那么应该这样写:
package cn.byr.nuanyangyang.interr;
public class InterruptibleSumFunc {
public static long sum(long low, long high) throws InterruptedException {
final long CHUNK_SIZE = 1024;
long s = 0;
for (long i = low; i <= high; i += CHUNK_SIZE) {
for (long j = i; j < i + CHUNK_SIZE; j++) {
s += j;
}
if (Thread.interrupted()) {
throw new InterruptedException(String.format("Sum calculation interrupted. Current i: %d, partial sum: %d", i, s));
}
}
return s;
}
public static void main(String[] args) throws InterruptedException {
Thread t = new Thread(() -> {
try {
long result = sum(0L, 1000000000L);
System.out.println("Finished. Result is " + result);
} catch (InterruptedException e) {
System.out.println("Interrupted.");
// Thread.currentThread().interrupt();
// I know it is the whole job, so no need to re-set the flag.
}
});
System.out.println("Start calculating...");
t.start();
Thread.sleep(1000);
t.interrupt();
t.join();
}
}
有时候,你想要把处理异常的责任抛给调用者,但由于要实现某种接口的原因,你不能抛出InterruptedException异常。通常是因为实现了Runnable接口。这种情况,可以在捕获异常的时候重新设置interrupted标志,这样,调用着紧接着检查Thread.interrupted()的时候,还会接受到这个标志。同时,随后的标准库函数,如sleep, wait等,也会因为这个标志而立即终止。
建议:如果你是写一个可重用的Runnable作业,那么一旦检测到被中断(截获InterruptedException,或者Thread.isinterrupted()为true),应该在Runnable.run()退出之前,重新设置interrupted标志。因为你永远不知道是不是有人在把你的作业组合到更大的作业里去。
package cn.byr.nuanyangyang.interr;
class SleepJob implements Runnable {
@Override
public void run() {
try {
System.out.println("Started sleeping.");
Thread.sleep(1000);
System.out.println("Finished sleeping.");
} catch (InterruptedException e) {
Thread.currentThread().interrupt(); // Re-set the interrupted flag.
}
}
}
public class MultiSleep {
public static void main(String[] args) throws InterruptedException {
Thread sleeperThread = new Thread(() -> {
Runnable job1 = new SleepJob();
Runnable job2 = new SleepJob();
Runnable job3 = new SleepJob();
job1.run();
if (Thread.interrupted()) {
System.out.println("Interrupted in job1. Stop.");
return;
}
job2.run();
if (Thread.interrupted()) {
System.out.println("Interrupted in job2. Stop.");
return;
}
job3.run();
if (Thread.interrupted()) {
System.out.println("Interrupted in job3. Stop.");
return;
}
});
sleeperThread.start();
Thread.sleep(1500);
sleeperThread.interrupt();
sleeperThread.join();
}
}
这是一条镜像帖。来源:北邮人论坛 / java / #41451同步于 2015/6/8
该镜像源已超过 30 天没有更新,可能在源站已被删除。
Java机器人发帖
InterruptedException是干什么用的?
nuanyangyang
2015/6/8镜像同步57 回复
订阅后,新回复会通过你的通知中心匿名送达。
9 条回复
【 在 Monologue 的大作中提到: 】
: 明白了~~
: 之前的代码的问题在于发生中断异常之后并没有真正的中断线程
: 这样理解对吗?
嗯。是的。如果直接catch然后e.printStackTrace(),意思是“我已经处理了这个异常,现在已经恢复正常了”(当然实际上没有“恢复正常”),所以线程不会中断。
我擦,我终于明白为什么Thread.sleep()需要try-catch了
【 在 nuanyangyang (暖羊羊) 的大作中提到: 】
: Interrupt是什么意思?
: Java里,每个线程都有一个“interrupted”标志。如果调用这个线程的interrupt()方法,就会设置这个标志。这个标记的意思是建议该线程停止。
: 可以使用Thread.interrupted()静态方法检测当前线程是否被中断。如果检测到true,那么同时会清除当前线程的interrupt标记。
: ...................