今天我们聊聊 Java 线程的中断机制。

线程中断机制提供了一种方法,用于将线程从阻塞等待中唤醒,并作出相应的“受控中断”处理。

synchronized (lock) {
try {
while (!check()) {
lock.wait(1000);
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}

这段代码使用了 Java 提供的 wait/notify 机制,线程执行 lock.wait() 会阻塞,有三种情况使线程恢复运行。

  1. 超时 1000ms 结束,正常执行下一句代码。

  2. 另一个线程执行下述代码主动唤醒

    synchronized (lock) {
    lock.notifyAll(); // or lock.notify();
    }

    这也会正常执行下一句代码。

  3. 另一个线程要求等待的线程“中断”

    // 拿到等待中的线程的引用
    Thread a;
    a.interrupt();

    被“中断”的线程 a,会在 lock.wait() 处抛出 InterruptedException 异常。

综上所述,你可以认为 object.wait() 内部在做这些事:

boolean checkTimeout = timeout > 0;
Thread current = Thread.currentThread();
lock.addWaiter(current);
while (!current.isNotified()) {
if (current.isInterrupted()) {
current.clearInterrupted();
throw new InterruptedException();
}
if (checkTimeout) {
if (timeout == 0) break;
timeout--;
}
}

这不完全准确,因为 wait 不使用这种“忙轮询”的方式做检查,但关于标志位的判断逻辑是正确的。

让我们从手动中断开始探究,

// sun.nio.ch.Interruptible

public interface Interruptible {
void interrupt(Thread var1);
} // java.lang.Thread private volatile Interruptible blocker;
private final Object blockerLock = new Object(); public void interrupt() {
if (this != Thread.currentThread())
checkAccess(); synchronized (blockerLock) {
Interruptible b = blocker;
if (b != null) {
interrupt0();
b.interrupt(this);
return;
}
}
interrupt0();
} // Just to set the interrupt flag
private native void interrupt0();

能够看出, thread.interrupt() 先判断权限,然后实际调用 interrupt0() 设置线程的中断标志,如果当前线程有 nio 的 Interruptible 那么还会回调它。

注意,interrupt0() 只是设置了线程的中断标志。

一个线程怎么知道自己被打断了?

// java.lang.Thread

public static boolean interrupted() {
return currentThread().isInterrupted(true);
} public boolean isInterrupted() {
return isInterrupted(false);
} private native boolean isInterrupted(boolean clearInterrupted);

也就是说, isInterrupted(boolean) 会返回线程是否被打断,并根据需要清空中断标志。

我们发现,当一个线程并不阻塞,没有在 object.wait() , thread.join() , Thread.sleep()等不受 Java 程序逻辑控制的区域时,那么线程是否被打断只能通过检查中断标志得知。

当一个函数调用可能阻塞,Java 会在阻塞的源头签名里标记 throws InterruptedException ,并要求编写 try catch 处理中断。

当线程阻塞,就像上文所述,Java 检查到中断标志,先将其清除,然后抛出 InterruptedException 。

// java.lang.Object

public final void wait() throws InterruptedException {
wait(0);
} public final native void wait(long timeout) throws InterruptedException;

如果一个线程收到 InterruptedException ,之后仍然执行了会引发阻塞的代码,它将像“没事人”一样继续阻塞住。因为 Java 在内部将中断标志清除了!

我们常见地编写以下三类处理 InterruptedException 的代码:

将 InterruptedException 交由上层处理。

public void foo() throws InterruptedException {
synchronized (lock) {
lock.wait();
}
}

遇到 InterruptedException 重设中断标志位。

try {
synchronized (lock) {
lock.wait();
}
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
//break;
}

先忙完,再重新抛出 InterruptedException 。

public void bar() throws InterruptedException {
InterruptedException ie = null;
boolean done = false;
while (!done) {
synchronized (lock) {
try {
lock.wait();
} catch (InterruptedException e) {
ie = e;
continue;
}
}
done = true;
}
if (ie != null) {
throw ie;
}
}

如果一个线程无视中断标志和 InterruptedException ,它仍然能够跑的很好。但 这与我们设计多线程的初衷是违背的 ,我们希望线程之间是和谐的有序协作以实现特定功能,因此 受控线程应当对中断作出响应 。而 Java 留给开发者这一自由,我们应当予以善用。如果你想学习java可以加我的学习群669823128

Java 线程的中断机制的更多相关文章

  1. 并发基础(八) java线程的中断机制

    文章转载自 详细分析Java中断机制 1. 引言 当我们点击某个杀毒软件的取消按钮来停止查杀病毒时,当我们在控制台敲入quit命令以结束某个后台服务时--都需要通过一个线程去取消另一个线程正在执行的任 ...

  2. java 线程中断机制

    上一篇文章我们了解过了java有关线程的基本概念,有线程的属性,线程可能处于的状态,还有线程的两种创建的方式,最后还说了一个关键字synchronized,解决了高并发导致数据内容不一致问题,本篇文章 ...

  3. java 多线程6: 中断机制 优雅的终止java线程

    前文 java 多线程5: java 终止线程及中断机制 (stop().interrupt() .interrupted().isInterrupted()) 使用 interrupt() 和 in ...

  4. 【转载】 Java线程面试题 Top 50

    Java线程面试题 Top 50 不管你是新程序员还是老手,你一定在面试中遇到过有关线程的问题.Java语言一个重要的特点就是内置了对并发的支持,让Java大受企业和程序员 的欢迎.大多数待遇丰厚的J ...

  5. Java线程面试题 Top 50 (转载)

    转载自:http://www.cnblogs.com/dolphin0520/p/3958019.html 原文链接:http://www.importnew.com/12773.html   本文由 ...

  6. 50 道 Java 线程面试题(转载自牛客网)

    下面是 Java 线程相关的热门面试题,你可以用它来好好准备面试. 1) 什么是线程? 线程是操作系统能够进行运算调度的最小单位,它被包含在进程之中,是进程中的实际运作单位.程序员可以通过它进行多处理 ...

  7. Java线程面试题 Top 50

    转自:http://www.importnew.com/12773.html 不管你是新程序员还是老手,你一定在面试中遇到过有关线程的问题.Java语言一个重要的特点就是内置了对并发的支持,让Java ...

  8. 【多线程】Java线程面试题 Top 50(转载)

    Java线程面试题 Top 50 原文链接:http://www.importnew.com/12773.html   本文由 ImportNew - 李 广 翻译自 javarevisited.欢迎 ...

  9. Java线程面试题 Top 50(转载)

    原文链接:http://www.importnew.com/12773.html 本文由 ImportNew - 李 广 翻译自 javarevisited.欢迎加入Java小组.转载请参见文章末尾的 ...

随机推荐

  1. vim批量注释与取消批量注释(转)

    方法一 块选择模式 插入注释: 用v进入virtual(可视化)模式(可以省略这一步) 用上下键选中需要注释的行数 按ctrl+v进入可视化块模式 按大写I进入插入模式,输入注释符‘#’或者是‘//’ ...

  2. ORA-00911: 无效字符\n

    使用EXECUTE IMMEDIATE执行命令时命令字符串不能添加命令结束符";",否则会报此错

  3. js使用经验之谈

    1.  js 对象,先有的起作用.CSS属性,后有的起作用. 2. 方法中使用submit提交表单,如果提交后面还有代码需要执行,不能保证顺序.例如,提交后关闭页面,很可能会在提交前关闭页面,导致提交 ...

  4. hadoop12---java并发编程的一些总结

    java并发编程的一些总结 %.1.不应用线程池的缺点 有些开发者图省事,遇到需要多线程处理的地方,直接new Thread(...).start(),对于一般场景是没问题的,但如果是在并发请求很高 ...

  5. springboot-vue项目后台2---pojo对查询结果手动分组

    <resultMap id="PResult" type="packs" > <result column="device_type ...

  6. lock关键字的用法

    一直以来对于lock关键字的用法都存有疑惑,也从网上看到很多关于他的资料包括MSDN,无奈MSDN讲述的真是让人上火.今天决定小小研究一下 一直都知道lock是锁定某一变量从而实现对某一代码段的独占执 ...

  7. autofac.webapi2

    quick start https://autofaccn.readthedocs.io/en/latest/integration/webapi.html#quick-start To get Au ...

  8. SpringMVC下文件的上传与下载以及文件列表的显示

    1.配置好SpringMVC环境-----SpringMVC的HelloWorld快速入门! 导入jar包:commons-fileupload-1.3.1.jar和commons-io-2.4.ja ...

  9. Softmax回归 softMax回归与logistic回归的关系

    简介 在本节中,我们介绍Softmax回归模型,该模型是logistic回归模型在多分类问题上的推广,在多分类问题中,类标签  可以取两个以上的值. Softmax回归模型对于诸如MNIST手写数字分 ...

  10. cvSmooth函数 和 OpenCV自带的人脸检测

    记录cvSmooth函数的用法和 OpenCV自带的人脸检测. (1)cvSmooth函数 void cvSmooth( const CvArr* src, CvArr* dst,int smooth ...