如何中断处于阻塞状态的线程?附Java代码示例分析
如何中断处于阻塞状态的线程?
首先直接给结论:不是所有阻塞状态都能被直接中断,这取决于线程阻塞的原因。我们先拆解你给出的例子,再一步步说明解决方案。
你的例子分析
在你的代码里,线程t2一开始是阻塞在synchronized (MUTEX)的锁等待队列中——Java的内置synchronized锁的等待是不可中断的。这时候调用t2.interrupt()只会给t2设置一个中断标记,但不会让它退出锁等待。只有当t1释放锁后,t2拿到锁进入Thread.sleep()时,sleep()方法会检查中断标记,抛出InterruptedException,这时候中断才生效。
不同阻塞类型的中断方式
Java里的线程阻塞主要分两类,对应不同的中断策略:
- 可中断阻塞:这类阻塞会响应
interrupt()调用,比如Thread.sleep()、Object.wait()、Thread.join(),以及java.util.concurrent包下的可中断锁等待(比如ReentrantLock.lockInterruptibly())。当线程处于这些阻塞状态时,调用interrupt()会让线程抛出InterruptedException,并清除中断标记。 - 不可中断阻塞:比如等待
synchronized内置锁、传统IO的阻塞(如Socket.accept()),这类阻塞不会响应interrupt(),调用interrupt()只会设置线程的中断标记,但线程会继续阻塞直到拿到锁/IO操作完成。
让锁等待可中断的解决方案
如果你想让线程在等待锁的时候就能被中断,不要用synchronized,改用java.util.concurrent.locks.ReentrantLock的lockInterruptibly()方法,它支持在等待锁时响应中断。
修改你的代码如下:
import java.util.concurrent.locks.ReentrantLock; public class Main implements Runnable { static ReentrantLock LOCK = new ReentrantLock(); public static void main(String[] args) throws Exception { Thread t1 = new Thread(new Main()); Thread t2 = new Thread(new Main()); System.out.println(t1.getId()); System.out.println(t2.getId()); t1.start(); Thread.sleep(1000); t2.start(); t2.interrupt(); System.out.println("done main thread"); } @Override public void run() { try { // 使用可中断的锁获取方式 LOCK.lockInterruptibly(); try { System.out.println(Thread.currentThread().getId()); Thread.sleep(1000 * 10); } finally { LOCK.unlock(); } } catch (InterruptedException ix) { System.out.println("Interrupt exception for:" + Thread.currentThread().getId()); return; } System.out.println("done" + Thread.currentThread().getId()); } }
这个版本里,t2在调用lockInterruptibly()等待锁时,t2.interrupt()会直接触发InterruptedException,不需要等到进入sleep()再生效。
其他阻塞场景的中断
- 对于传统IO阻塞(比如
InputStream.read()),这类操作不会响应中断,你可以通过关闭流/套接字的方式让线程退出阻塞。 - 对于NIO的通道(
java.nio.channels.Channel),大多数支持中断,调用interrupt()会让阻塞的IO操作抛出ClosedByInterruptException。
内容的提问来源于stack exchange,提问作者Aladdin
相关产品推荐
相关产品推荐

