今天我们聊聊 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. 【转】Python爬虫(7)_scrapy-redis

    scrapy-redis使用以及剖析   scrapy-redis是一个基于redis的scrapy组件,通过它可以快速实现简单分布式爬虫程序,该组件本质上提供了三大功能: scheduler - 调 ...

  2. PHP HTML DOM 解析器 中文手册

    简单的PHP HTML DOM 解析器 中文手册 | PHP Simple HTML DOM Parser中文手册 目录 快速入门 如何创建HTML DOM 对象? 如何查找HTML元素? 如何访问H ...

  3. rabbitmq的发布确认和事务

    摘要: 介绍confirm的工作机制.使用spring-amqp介绍事务以及发布确认的使用方式.因为事务以及发布确认是针对channel来讲,所以在一个连接中两个channel,一个channel可以 ...

  4. c++中指针作为函数参数的详细理解

    在C语言中,函数的参数不仅可以是整数.小数.字符等具体的数据,还可以是指向它们的指针.用指针变量作函数参数可以将函数外部的地址传递到函数内部,使得在函数内部可以操作函数外部的数据,并且这些数据不会随着 ...

  5. Saltstack 命令参数整理

    命令:salt-key # 测试 命令:salt-key -A # 管理所有minion 命令:salt-key -a # 管理定义minion 命令:salt-key -d ID名字 # 删除单个m ...

  6. zabbix监控windows

    windows  版zabbix_agent下载地址: https://www.zabbix.com/download_agents 解压,有bin和conf两个文件夹 配置: 在windows被监控 ...

  7. 关于在asp.net添加jQuery的智能提示

    如果是vs2008以后的版本,一般都会支持jQuery自动提示代码功能,不支持也没关系,很简单的操作就能支持: 1.先为vs下载一个补丁,地址为:http://code.msdn.microsoft. ...

  8. Linux下使用USB模拟ACM串口设备【转】

    本文转载自:https://www.cnblogs.com/pied/p/4549614.html 这个想法之前就在脑袋里有过,最近公司产品要用到,所以多做了些了解. 1. USB 简介 USB 是 ...

  9. java处理图片base64编码的相互转换

    转载自http://www.cnblogs.com/libra0920/p/5754356.html 直接上代码 import sun.misc.BASE64Decoder; import sun.m ...

  10. Google protobuf序列化以及反序列化

    序列化的目的是将对象持久化到硬盘或者用于网络传输.java也提供了序列化技术,非常简单,只要实现Serializable接口即可.如下: public class commonService impl ...