在Java并发编程中,线程中断(Thread Interruption)是一种协作式的中断机制,它允许一个线程通知另一个线程"建议它停止当前操作"。这种机制与强制终止线程的stop()方法有本质区别——中断不会直接终止线程,而是设置一个标志位,由被中断线程自行决定如何响应。
关键实现原理:
重要区别:isInterrupted()不会清除中断标志,而Thread.interrupted()会在检测后清除标志位
当线程在执行以下方法时被中断,会立即抛出InterruptedException:
java复制Object.wait()
Thread.sleep()
Thread.join()
标准处理模板:
java复制try {
Thread.sleep(1000);
} catch (InterruptedException e) {
// 恢复中断状态(最佳实践)
Thread.currentThread().interrupt();
// 执行清理逻辑后退出
return;
}
对于CPU密集型运算,需要主动检查中断状态:
java复制while (!Thread.currentThread().isInterrupted()) {
// 执行计算任务
heavyCalculation();
// 或者使用静态方法检查(会清除标志位)
if (Thread.interrupted()) {
// 处理中断逻辑
break;
}
}
某些I/O操作(如Socket读写)不响应中断,此时需要:
Java线程中断的核心依赖于JVM与操作系统的协作:
cpp复制// os_linux.cpp
void os::interrupt(Thread* thread) {
pthread_kill(thread->osthread()->pthread_id(), SIGVTALRM);
}
中断标志的存储位置:
通过继承Thread实现更灵活的中断控制:
java复制class CustomThread extends Thread {
private volatile boolean shutdownRequested = false;
public void shutdown() {
shutdownRequested = true;
interrupt(); // 双保险
}
@Override
public void run() {
while (!shutdownRequested) {
try {
processTask();
} catch (InterruptedException e) {
if (!shutdownRequested) {
// 意外中断处理
logger.warn("Unexpected interruption");
}
}
}
}
}
ExecutorService提供了更完善的中断控制:
java复制ExecutorService executor = Executors.newFixedThreadPool(4);
Future<?> future = executor.submit(() -> {
while (!Thread.currentThread().isInterrupted()) {
// 任务逻辑
}
});
// 通过Future取消任务
future.cancel(true); // true表示尝试中断线程
在微服务场景中,可以通过以下模式实现类似中断的协作机制:
反例:
java复制// 错误示范:吞没中断异常
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
// 什么都不做!
}
标准资源清理模式:
java复制public void run() {
try {
while (!Thread.interrupted()) {
// 使用资源
useResource();
}
} finally {
// 确保资源释放
cleanupResource();
}
}
高频中断检查可能影响性能,可采用:
java复制private static final int CHECK_INTERVAL = 1000;
private int counter = 0;
void process() {
if (++counter % CHECK_INTERVAL == 0) {
if (Thread.interrupted()) {
throw new RuntimeException("Interrupted");
}
}
// 正常处理
}
| 现象 | 可能原因 | 解决方案 |
|---|---|---|
| interrupt()无效 | 线程处于不可中断I/O | 改用NIO或关闭底层资源 |
| 异常未被捕获 | 自定义了异常处理器 | 检查Thread.setUncaughtExceptionHandler |
| 标志位自动清除 | 使用了Thread.interrupted() | 改用isInterrupted() |
中断可能打破死锁的条件:
java复制final Object lock1 = new Object();
final Object lock2 = new Object();
Thread t1 = new Thread(() -> {
synchronized (lock1) {
try {
Thread.sleep(100); // 诱发死锁
synchronized (lock2) {}
} catch (InterruptedException e) {
// 中断后释放锁
}
}
});
code复制"Thread-0" #10 prio=5 os_prio=0 tid=0x00007f48740e8000 nid=0x5e03 waiting on condition [0x00007f486b7e7000]
java.lang.Thread.State: TIMED_WAITING (sleeping)
at java.lang.Thread.sleep(Native Method)
- interrupted java.lang.Thread.sleep(Native Method)
Java8的CompletableFuture提供了更灵活的中断控制:
java复制CompletableFuture.supplyAsync(() -> {
if (Thread.interrupted()) {
throw new CompletionException(new InterruptedException());
}
return doWork();
}).exceptionally(ex -> {
if (ex.getCause() instanceof InterruptedException) {
// 中断处理逻辑
}
return null;
});
在Reactor等响应式库中,使用dispose()作为中断的替代:
java复制Disposable disposable = Flux.interval(Duration.ofMillis(100))
.subscribe(i -> {
if (Thread.interrupted()) {
throw new RuntimeException("Interrupted");
}
});
// 相当于interrupt()
disposable.dispose();
Java19+的虚拟线程(Loom项目)改进了中断处理:
典型用法:
java复制try (var scope = new StructuredTaskScope.ShutdownOnFailure()) {
Future<String> future = scope.fork(() -> {
Thread.sleep(Duration.ofHours(1)); // 可被中断
return "Done";
});
scope.shutdown(); // 触发所有子线程中断
}