1. 使用interrupt()中断线程

当一个线程运行时,另一个线程可以调用对应的Thread对象的interrupt()方法来中断它,该方法只是在目标线程中设置一个标志,表示它已经被中断,并立即返回。这里需要注意的是,如果只是单纯的调用interrupt()方法,线程并没有实际被中断,会继续往下执行。如下代码所示:

  1. public class SleepInterrupt implements Runnable {
  2.  
  3. @Override
  4. public void run() {
  5.  
  6. try {
  7. System.out.println("子线程开始执行");
  8. Thread.sleep(20000);
  9. System.out.println("子线程继续执行");
  10. } catch (InterruptedException e) {
  11. System.out.println("子线程遇到中断异常");
  12. //处理完中断异常后,返回到run()方法入口
  13. //如果没有return,线程不会实际被中断,它会继续打印下面的信息
  14. return;
  15. }
  16. System.out.println("子线程执行结束");
  17. }
  18.  
  19. public static void main(String[] args) {
  20. SleepInterrupt si = new SleepInterrupt();
  21. Thread t = new Thread(si);
  22. t.start();
  23. //主线程休眠2秒,从而确保刚才启动的线程有机会执行一段时间
  24. try {
  25. Thread.sleep(2000);
  26. } catch (InterruptedException e) {
  27. e.printStackTrace();
  28. }
  29. System.out.println("主线程对子线程执行中断操作");
  30. //中断线程t
  31. t.interrupt();
  32. System.out.println("主线程结束执行");
  33. }
  34. }

主线程启动新线程后,自身休眠2秒钟,允许新线程获得运行时间。新线程打印信息“子线程开始执行”后,继而休眠20秒钟,大约2秒钟后,main线程通知新线程中断,那么新线程的20秒的休眠将被打断并抛出InterruptException异常,执行跳转到catch块,打印出“子线程遇到中断异常”信息后结束。

请注意:由于不确定的线程规划,上图运行结果的后两行可能顺序相反,这取决于主线程和新线程哪个先消亡。但前两行信息的顺序必定如上图所示。

另外,如果将catch块中的return语句注释掉,则线程在抛出异常后会继续往下执行,而不会被中断,从而会打印出”子线程执行结束”信息。

2.  待决中断

在上面的例子中,sleep()方法的实现检查到休眠线程被中断,它会相当友好地终止线程,并抛出InterruptedException异常。另外一种情况,如果线程在调用sleep()方法前被中断,那么该中断称为待决中断,它会在刚调用sleep()方法时,立即抛出InterruptedException异常。

  1. public class PendingInterrupt extends Object {
  2.  
  3. public static void main(String[] args) {
  4. //在main线程中中断当前线程(即main线程)
  5. Thread.currentThread().interrupt();
  6. //获取当前时间
  7. long startTime = System.currentTimeMillis();
  8. try {
  9. Thread.sleep(2000);
  10. System.out.println("没有被中断");
  11. } catch (InterruptedException e) {
  12. System.out.println("被中断");
  13. }
  14. //计算中间代码执行的时间
  15. System.out.println("执行耗时=" + (System.currentTimeMillis() - startTime));
  16. }
  17. }

这种模式下,main线程中断它自身。除了将中断标志(它是Thread的内部标志)设置为true外,没有其他任何影响。线程被中断了,但main线程仍然运行,main线程继续监视实时时钟并进入try块,一旦调用sleep()方法就会注意到待决中断的存在,并抛出InterruptException。于是执行跳转到catch块,并打印出线程被中断的信息。最后,计算并打印出时间差。最终输出的时间差距应该远小于2000。

3.  使用isInterrupted()方法判断中断状态

可以在Thread对象上调用isInterrupted()方法来检查任何线程的中断状态。

这里需要注意:线程一旦被中断isInterrupted()方法便会返回true,而一旦sleep()方法抛出异常,它将清空中断标志,此时isInterrupted()方法将返回false。下面的代码演示了isInterrupted()方法的使用:

  1. public class InterruptCheck{
  2.  
  3. public static void main(String[] args) {
  4. Thread t = Thread.currentThread();
  5. System.out.println("Point A: t.isInterrupted()=" + t.isInterrupted());
  6. //待决中断,中断自身
  7. t.interrupt();
  8. System.out.println("Point B: t.isInterrupted()=" + t.isInterrupted());
  9. System.out.println("Point C: t.isInterrupted()=" + t.isInterrupted());
  10.  
  11. try {
  12. Thread.sleep(2000);
  13. System.out.println("was NOT interrupted");
  14. } catch (InterruptedException e) {
  15. System.out.println("was interrupted");
  16. }
  17. //跑出异常后,会清除中断标志,这里会返回false
  18. System.out.println("Point D: t.isInterrupted()=" + t.isInterrupted());
  19. }
  20.  
  21. }

4.  使用Thread.interrupted()方法判断中断状态

可以使用Thread.interrupted()方法来检查当前线程的中断状态(并隐式重置为false)。又由于它是静态方法,因此不能在特定的线程上使用,而只能报告调用它的线程的中断状态,如果线程被中断,而且中断状态尚不清楚,那么这个方法返回true。与isInterrupted()不同,它将自动重置中断状态为false,第二次调用Thread.interrupted()方法,总是返回false,除非中断了线程。

如下代码演示了Thread.interrupted()方法的使用:

  1. public class InterruptReset{
  2.  
  3. public static void main(String[] args) {
  4. System.out.println(
  5. "Point X: Thread.interrupted()=" + Thread.interrupted());
  6. Thread.currentThread().interrupt();
  7. System.out.println(
  8. "Point Y: Thread.interrupted()=" + Thread.interrupted());
  9. System.out.println(
  10. "Point Z: Thread.interrupted()=" + Thread.interrupted());
  11. }
  12.  
  13. }

Java并发——线程中断学习的更多相关文章

  1. Java 并发 线程同步

    Java 并发 线程同步 @author ixenos 同步 1.异步线程本身包含了执行时需要的数据和方法,不需要外部提供的资源和方法,在执行时也不关心与其并发执行的其他线程的状态和行为 2.然而,大 ...

  2. Java 并发 线程属性

    Java 并发 线程属性 @author ixenos 线程优先级 1.每当线程调度器有机会选择新线程时,首先选择具有较高优先级的线程 2.默认情况下,一个线程继承它的父线程的优先级 当在一个运行的线 ...

  3. Java 并发 线程的优先级

    Java 并发 线程的优先级 @author ixenos 低优先级线程的执行时刻 1.在任意时刻,当有多个线程处于可运行状态时,运行系统总是挑选一个优先级最高的线程执行,只有当线程停止.退出或者由于 ...

  4. Java 并发 线程的生命周期

    Java 并发 线程的生命周期 @author ixenos 线程的生命周期 线程状态: a)     New 新建 b)     Runnable 可运行 c)     Running 运行 (调用 ...

  5. 从JDK源码角度看java并发线程的中断

    线程的定义给我们提供了并发执行多个任务的方式,大多数情况下我们会让每个任务都自行执行结束,这样能保证事务的一致性,但是有时我们希望在任务执行中取消任务,使线程停止.在java中要让线程安全.快速.可靠 ...

  6. Java并发编程深入学习

    上周的面试中,被问及了几个并发开发的问题,自己回答的都不是很系统和全面,可以说是"头皮发麻",哈哈.因此果断购入<Java并发编程的艺术>一书,该书内容主要是对ifev ...

  7. Java并发——线程介绍

    前言: 互联网时代已经发展到了现在.从以前只考虑小流量到现在不得不去考虑高并发的问题.扯到了高并发的问题就要扯到线程的问题.你是否问过自己,你真正了解线程吗?还是你只知道一些其他博客里写的使用方法.下 ...

  8. Java并发编程快速学习

    上周的面试中,被问及了几个关于Java并发编程的问题,自己回答的都不是很系统和全面,可以说是"头皮发麻",哈哈.因此果断购入<Java并发编程的艺术>一书,学习后的体会 ...

  9. Java并发——线程间的等待与通知

    前言: 前面讲完了一些并发编程的原理,现在我们要来学习的是线程之间的协作.通俗来说就是,当前线程在某个条件下需要等待,不需要使用太多系统资源.在某个条件下我们需要去唤醒它,分配给它一定的系统资源,让它 ...

随机推荐

  1. 实践:配置keepalived实现主备热备份功能

    图: 配置文件: 主服务器的配置如下: global_defs { router_id NodeA}vrrp_instance VI_1 { state MASTER #设置为主服务器 interfa ...

  2. Gitlab--安装及汉化

    简介 gitlab是一个利用 Ruby on Rails 开发的开源应用程序,实现一个自托管的Git 项目仓库,可通过Web界面迚行访问公开的戒者私人项目.Ruby on Rails 是一个可以使你开 ...

  3. loadrunner 场景设计-手工场景设计

    场景设计-手工场景设计 by:授客 QQ:1033553122 概述 通过选择需要运行的脚本,分配运行脚本的负载生成器,在脚本中分配Vuser来建立手工场景 手工场景就是自行设置虚拟用户的变化,主要是 ...

  4. redis介绍 (8) window 下redis的集群(cluster命令)

    前言: 前段时间我在centos上搭建过一次redis集群,那是借助ruby搭建,这次我介绍一种纯redis集群命令的方式去搭建[最后我会简单介绍ruby搭建]. redis集群搭建(三主三备): 准 ...

  5. android recovery 升级UI显示之资源文件

    Recovery只有在升级的时候才会呈现给用户,所以界面一般都很简单,没有android上层那么绚丽,所以recovery下面对图片的支持很有限,仅支持png图片显示,所以我们可以看到,recover ...

  6. echart参数设置——曲线图

    { title: { text: '请求返回码分布', subtext: '实时数据' }, tooltip: { trigger: 'axis', position: function (point ...

  7. [20180319]直接路径读特例12c.txt

    [20180319]直接路径读特例12c.txt --//昨天的测试突然想起以前遇到的直接路径读特例,在12c重复测试看看. 1.环境:SCOTT@test01p> @ ver1 PORT_ST ...

  8. Pyhon环境变量的一些坑

    在正常的情况下,使用编译器执行Python文件,无需考虑环境变量的改变 例:sum --one --one1.py --two --two1.py 在执行one.py文件需要调用 two.py中某个方 ...

  9. EntityFramework Code-First 简易教程(五)-------领域类配置

    前言:在前篇中,总是把领域类(Domain Class)翻译成模型类,因为我的理解它就是一个现实对象的抽象模型,不知道对不对.以防止将来可能的歧义,这篇开始还是直接对Domain Class直译. 前 ...

  10. sklearn datasets模块学习

    sklearn.datasets模块主要提供了一些导入.在线下载及本地生成数据集的方法,可以通过dir或help命令查看,我们会发现主要有三种形式:load_<dataset_name>. ...