计算机世界所说的中断
谈到中断,我们总是习惯性的想到中断就是将正在进行这件事打断。但是,在计算机世界,中断可能不是这么简单。从计算机设计的角度考虑,如果中断就是强行打断某些正在进行中的线程的话,这很可能造成不可挽回的后果。
所以,计算机对于打断的设计得更圆滑一点,当我们需要进行打断操作的时候,计算机仅仅是做一个打断的通知,具体什么时候打断,由收到打断信号的线程自己做决定。
为什么需要中断机制
在日常开发中,我们不能保证每一个线程都会按照我们预期的方向执行下去,总会由于一些问题导致线程处于自旋浪费资源的状态。
关于自旋的概念可以参考这篇文章
# 互斥锁与自旋锁
java中的中断方法
interrupt
从源码中不难看出,这个是线程类唯一一个可以设置中断状态的方法,其实现原理也很简单,直接调用native方法interrupt0完成设置中断( 简单地讲,一个Native Method就是一个java调用非java代码的接口。一个Native Method是这样一个java的方法:该方法的实现由非java语言实现,比如C。这个特征并非java所特有,很多其它的编程语言都有这一机制,比如在C++中,你可以用extern “C”告知C++编译器去调用一个C的函数。)。
public void interrupt() {
if (this != Thread.currentThread())
checkAccess();
synchronized (blockerLock) {
Interruptible b = blocker;
if (b != null) {
interrupt0(); // Just to set the interrupt flag
b.interrupt(this);
return;
}
}
interrupt0();
}
复制代码
interrupted
这个函数通过源码我们不难看出,他会判断当前线程的中断状态,若被中断则返回true,且会将中断状态的标记设置为false。
public static boolean interrupted() {
return currentThread().isInterrupted(true);
}
复制代码
/**
* Tests if some Thread has been interrupted. The interrupted state
* is reset or not based on the value of ClearInterrupted that is
* passed.
*/
private native boolean isInterrupted(boolean ClearInterrupted);
复制代码
可能有些读者读到这里会有点不明白这个方法的含义,我们就以一段代码对这个方法进行解释
Thread.currentThread().isInterrupted(); // true 当前线程已被中断
Thread.interrupted() // true,表示当前线程已被中断,然后将中断标记设置为false
Thread.currentThread().isInterrupted(); // false
Thread.interrupted() // false
复制代码
isInterrupted
这个函数不必多说,当线程被中断则返回true,若被清除中断状态(即被上述的interrupted清除了true的状态标记)或者还未中断则返回false。
public boolean isInterrupted() {
return isInterrupted(false);
}
复制代码
使用中断的注意事项
原则1
如果调用可被中断的方法,那么他的方法签名上必然会有throw InterruptedException,当你在调用过程中抛出InterruptedException时,你可以不断将其向上抛出,是当前方法成为一个可被中断的方法。确保这个方法遇到故障时也能被成功检测并中断。
原则2
当然,你可能会在日常开发中无法做到总是抛出InterruptedException,所以为了保证故障的线程能被成功中断,对于没有加上throw InterruptedException的方法,必须捕获这个异常,并手动将其中断,如下所示:
Thread th = Thread.currentThread();
while (true) {
if (th.isInterrupted()) {
break;
}
// todo something
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
//在catch时将其打断,否则就会无线循环,线程永不停止
th.interrupt();
}
}
复制代码
* @throws InterruptedException
* if any thread has interrupted the current thread. The
* <i>interrupted status</i> of the current thread is
* cleared when this exception is thrown.
*/
public static native void sleep(long millis) throws InterruptedException;
复制代码
可以看出这段代码中线程调用了sleep,但是翻看sleep代码注释我们发现,当休眠发生异常时会抛出InterruptedException当前线程的中断状态会被重置。所以为了保证线程能够跳出while,我们必须在catch块中将其手动设置中断标记以确保出错时,这个野线程能够被及时中断而避免资源浪费。
从源码中查看中断
ThreadPoolExecutor shutdownNow
我们自顶向下可以看出,shutdownNow底层就是通过interrupt来中断所有的工作线程。
public List<Runnable> shutdownNow() {
List<Runnable> tasks;
final ReentrantLock mainLock = this.mainLock;
mainLock.lock();
try {
checkShutdownAccess();
advanceRunState(STOP);
interruptWorkers();
tasks = drainQueue();
} finally {
mainLock.unlock();
}
tryTerminate();
return tasks;
}
复制代码
private void interruptWorkers() {
final ReentrantLock mainLock = this.mainLock;
mainLock.lock();
try {
for (Worker w : workers)
w.interruptIfStarted();
} finally {
mainLock.unlock();
}
}
复制代码
void interruptIfStarted() {
Thread t;
if (getState() >= 0 && (t = thread) != null && !t.isInterrupted()) {
try {
t.interrupt();
} catch (SecurityException ignore) {
}
}
}
复制代码
FutureTask cancel
public boolean cancel(boolean mayInterruptIfRunning) {
if (!(state == NEW &&
UNSAFE.compareAndSwapInt(this, stateOffset, NEW,
mayInterruptIfRunning ? INTERRUPTING : CANCELLED)))
return false;
try { // in case call to interrupt throws exception
if (mayInterruptIfRunning) {
try {
Thread t = runner;
if (t != null)
t.interrupt();
} finally { // final state
UNSAFE.putOrderedInt(this, stateOffset, INTERRUPTED);
}
}
} finally {
finishCompletion();
}
return true;
}
复制代码




近期评论