InterruptedException
在我们使用一些线程相关的方法时,例如sleep
, 该方法会抛出一个InterruptedException
,
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
相关的还有BlockingQueue.put/take
等方法, 都会抛出InterruptedException
异常,
为什么会有这个异常呢?
举一个例子,在日常的电脑使用过程中,我们可能会在电脑中搜索某个文件,这时候假设计算机开启多个线程帮我们去查找这个文件,
当其中一个线程搜索到这个文件以后,意味着其他的线程已经不需要继续查找了,所以这时候需要一个能让其他线程停止工作的功能,
在java的Thread
线程类中,存在一个名叫interrupt
的方法, 这个方法是用于中断调用该方法的线程,该方法是通过一个标志位的设置,让被设置的线程进行中断操作,
public static void main(String[] args) throws InterruptedException {
Thread newThread = new Thread(() -> {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
System.out.println("我被中断了");
e.printStackTrace();
}
});
newThread.start();
Thread.sleep(500);
newThread.interrupt();
}
运行上面的代码,得到结果:
翻译一下上面代码的意思,开启一个线程,并让该线程睡眠1秒钟,随后主线程睡眠500毫秒,主线程恢复运行后,
调用了newThread
的interrupt
方法,告诉它,你需要中断了,
随后newThread
收到了这个消息,发生中断异常,停止睡眠,结束运行。
这里提出两个问题,
- 任何线程都可以被中断吗?
看如下代码:
public static void main(String[] args) throws InterruptedException {
Thread newThread = new Thread(() -> {
try {
int i = 0;
while (true) {
i++;
test();
}
} catch (InterruptedException e) {
System.out.println("我被中断了");
e.printStackTrace();
}
});
newThread.start();
Thread.sleep(500);
newThread.interrupt();
}
public static void test() throws InterruptedException {
}
我们将之前的睡眠方法改造了一下,一个死循环调用了一个抛出InterruptedException
却什么也没做的方法,
同时主线程休眠了500
毫秒以后,发出中断信号,此时却发现,newThread
线程并没有中断,而是继续在执行,
可以通过jstack
命令,查看该线程的状态,在不停的RUNNABLE
,说明中断信号完全没用,
此刻可以得出一个结论,并不是所有的线程都可以被中断的,会不会被中断,取决于该线程自己的决定,
在java当中,已经定义好的一些抛出InterruptedException
的类库方法,会响应中断命令,进行中断,
但是一些用户自己实现的方法中,并不会。
- 中断只能发生在这些方法里吗?
取决于线程自己的策略, JVM
中的阻塞方法都会正常响应中断信号,
什么是阻塞方法?
阻塞方法就是使得当前线程陷入一个等待的状态,并不占用CPU,而是暂停住,等一个信号让他恢复执行,或者等一个信号让他中断,例如Thread
的sleep
方法,
还有BlockingQueue
,一个java提供的阻塞队列,当生产者向队列中存放数据时,如果队列已经满了,
该步骤将进入阻塞状态,知道该队列有足够的空间,存放下要放入的数据,
当消费者消费数据时,也是一样,如果有数据时,队列将会立马返回,如果没有数据,该步骤也将进入阻塞状态。