我的编程空间,编程开发者的网络收藏夹
学习永远不晚

如何理解线程中断的问题

短信预约 -IT技能 免费直播动态提醒
省份

北京

  • 北京
  • 上海
  • 天津
  • 重庆
  • 河北
  • 山东
  • 辽宁
  • 黑龙江
  • 吉林
  • 甘肃
  • 青海
  • 河南
  • 江苏
  • 湖北
  • 湖南
  • 江西
  • 浙江
  • 广东
  • 云南
  • 福建
  • 海南
  • 山西
  • 四川
  • 陕西
  • 贵州
  • 安徽
  • 广西
  • 内蒙
  • 西藏
  • 新疆
  • 宁夏
  • 兵团
手机号立即预约

请填写图片验证码后获取短信验证码

看不清楚,换张图片

免费获取短信验证码

如何理解线程中断的问题

本篇内容主要讲解“如何理解线程中断的问题”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“如何理解线程中断的问题”吧!

实现线程本质上只有一种方式

为什么不强制停止

对于 Java 而言,最正确的停止线程的方式是使用 interrupt。但  interrupt仅仅起到通知被停止线程的作用。而对于被停止的线程而言,它拥有完全的自主权,它既可以选择立即停止,也可以选择一段时间后停止,也可以选择压根不停止。

为什么 Java 不提供强制停止线程的能力呢?事实上,Java  希望程序间能够相互通知、相互协作地管理线程,因为如果不了解对方正在做的工作,贸然强制停止线程就可能会造成一些安全的问题。

比如:线程正在写入一个文件,这时收到终止信号,它就需要根据自身业务判断,是选择立即停止,还是将整个文件写入成功后停止。如果选择立即停止就可能造成数据不完整,不管是中断命令发起者,还是接收者都不希望数据出现问题。

如何用 interrupt 停止线程

while (!Thread.currentThread().isInterrupted()  && more work to do) {     do more work }

我们一旦调用某个线程的 interrupt()  之后,这个线程的中断标记位就会被设置成true。每个线程都有这样的标记位,当线程执行时,应该定期检查这个标记位,如果标记位被设置成  true,就说明有程序想终止该线程。

回到源码,可以看到在 while 循环体判断语句中,首先通过

Thread.currentThread().isInterrupt()

判断线程是否被中断,随后检查是否还有工作要做。&& 逻辑表示只有当两个判断条件同时满足的情况下,才会去执行下面的工作。

public class StopThread implements Runnable {       @Override     public void run() {         int count = 0;         while (!Thread.currentThread().isInterrupted() && count < 1000) {             System.out.println("count = " + count++);         }     }       public static void main(String[] args) throws InterruptedException {         Thread thread = new Thread(new StopThread());         thread.start();         Thread.sleep(5);         thread.interrupt();     } }

在 StopThread 类的 run() 方法中,首先判断线程是否被中断,然后判断 count 值是否小于 1000。

这个线程的工作内容很简单,就是打印 0~999 的数字,每打印一个数字 count 值加  1,可以看到,线程会在每次循环开始之前,检查是否被中断了。接下来在 main 函数中会启动该线程,然后休眠 5  毫秒后立刻中断线程,该线程会检测到中断信号,于是在还没打印完1000个数的时候就会停下来,这种就属于通过 interrupt 正确停止线程的情况。

sleep 期间能否感受到中断

先说结论,可以。

public class StopDuringSleep {       public static void main(String[] args) throws InterruptedException {         Runnable runnable = () -> {             int num = 0;             try {                 while (!Thread.currentThread().isInterrupted() && num <= 1000) {                     System.out.println(num);                     num++;                     Thread.sleep(1000000);                 }             } catch (InterruptedException e) {                 e.printStackTrace();             }         };         Thread thread = new Thread(runnable);         thread.start();         Thread.sleep(5);         thread.interrupt();     } }

运行后的结果你猜怎么着,程序会抛出异常

如何理解线程中断的问题

如果 sleep、wait  等可以让线程进入阻塞的方法使线程休眠了,而处于休眠中的线程被中断,那么线程是可以感受到中断信号的,并且会抛出一个 InterruptedException  异常,同时清除中断信号,将中断标记位设置成  false。这样一来就不用担心长时间休眠中线程感受不到中断了,因为即便线程还在休眠,仍然能够响应中断通知,并抛出异常。

但是这样只能相应一次中断信号了,怎么办?我的业务还没有完成收尾,怎么办?

合理利用好 try/catch

我们在实际开发中不能盲目吞掉中断,如果不在方法签名中声明,也不在 catch 语句块中再次恢复中断,而是在 catch  中不作处理,我们称这种行为是“屏蔽了中断请求”。如果我们盲目地屏蔽了中断请求,会导致中断信号被完全忽略,最终导致线程无法正确停止。

try {         Thread.sleep(2000);     } catch (InterruptedException e) { //        此处处理中断异常请求,业务收尾     }

停止线程的方式有几种

void shutdown; boolean isShutdown; boolean isTerminated; boolean awaitTermination(long timeout, TimeUnit unit) throws InterruptedException; List<Runnable> shutdownNow;

下面我们就对这些方法逐一展开。

shutdown()

调用 shutdown() 方法之后线程池并不是立刻就被关闭,因为这时线程池中可能还有很多任务正在被执行,或是任务队列中有大量正在等待被执行的任务,调用  shutdown() 方法后线程池会在执行完正在执行的任务和队列中等待的任务后才彻底关闭。但这并不代表 shutdown() 操作是没有任何效果的,调用  shutdown() 方法后如果还有新的任务被提交,线程池则会根据拒绝策略直接拒绝后续新提交的任务。

isShutdown()

它可以返回 true 或者 false 来判断线程池是否已经开始了关闭工作,也就是是否执行了 shutdown 或者 shutdownNow  方法。这里需要注意,如果调用 isShutdown() 方法的返回的结果为 true  并不代表线程池此时已经彻底关闭了,这仅仅代表线程池开始了关闭的流程,也就是说,此时可能线程池中依然有线程在执行任务,队列里也可能有等待被执行的任务。

isTerminated()

这个方法可以检测线程池是否真正“终结”了,这不仅代表线程池已关闭,同时代表线程池中的所有任务都已经都执行完毕了,因为我们刚才说过,调用 shutdown  方法之后,线程池会继续执行里面未完成的任务,不仅包括线程正在执行的任务,还包括正在任务队列中等待的任务。比如此时已经调用了 shutdown  方法,但是有一个线程依然在执行任务,那么此时调用 isShutdown 方法返回的是 true ,而调用 isTerminated 方法返回的便是 false  ,因为线程池中还有任务正在在被执行,线程池并没有真正“终结”。直到所有任务都执行完毕了,调用 isTerminated() 方法才会返回  true,这表示线程池已关闭并且线程池内部是空的,所有剩余的任务都执行完毕了。

awaitTermination()

第四个方法叫作 awaitTermination(),它本身并不是用来关闭线程池的,而是主要用来判断线程池状态的。比如我们给  awaitTermination 方法传入的参数是 10 秒,那么它就会陷入 10 秒钟的等待,直到发生以下三种情况之一:

  • 等待期间(包括进入等待状态之前)线程池已关闭并且所有已提交的任务(包括正在执行的和队列中等待的都执行完毕,相当于线程池已经“终结”了,方法便会返回true

  • 等待超时时间到后,第一种线程池“终结”的情况始终未发生,方法返回 false

  • 等待期间线程被中断,方法会抛出 Interruptedexception异常

等待期间(包括进入等待状态之前)线程池已关闭并且所有已提交的任务(包括正在执行的和队列中等待的)都执行完毕,相当于线程池已经“终结”了,方法便会返回  true;

等待超时时间到后,第一种线程池“终结”的情况始终未发生,方法返回 false;等待期间线程被中断,方法会抛出 InterruptedException  异常。

shutdownNow()

最后一个方法是 shutdownNow(),也是 5 种方法里功能最强大的,它与第一种 shutdown 方法不同之处在于名字中多了一个单词  Now,也就是表示立刻关闭的意思。在执行 shutdownNow 方法之后,首先会给所有线程池中的线程发送 interrupt  中断信号,尝试中断这些任务的执行,然后会将任务队列中正在等待的所有任务转移到一个 List 中并返回,我们可以根据返回的任务 List  来进行一些补救的操作,例如记录在案并在后期重试。

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;  }

源码中有一行 interruptWorkers()  代码,这行代码会让每一个已经启动的线程都中断,这样线程就可以在执行任务期间检测到中断信号并进行相应的处理,提前结束任务。这里需要注意的是,由于 Java  中不推荐强行停止线程的机制的限制,即便我们调用了 shutdownNow 方法,如果被中断的线程对于中断信号不理不睬,那么依然有可能导致任务不会停止。

到此,相信大家对“如何理解线程中断的问题”有了更深的了解,不妨来实际操作一番吧!这里是编程网网站,更多相关内容可以进入相关频道进行查询,关注我们,继续学习!

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

如何理解线程中断的问题

下载Word文档到电脑,方便收藏和打印~

下载Word文档

猜你喜欢

Java中线程安全问题该如何理解

这期内容当中小编将会给大家带来有关Java中线程安全问题该如何理解,文章内容丰富且以专业的角度为大家分析和叙述,阅读完这篇文章希望大家可以有所收获。线程安全问题是一个比较高深的问题,是很多程序员比较难掌握的一个技术难点,如果一个程序员对线程
2023-06-17

如何解决网络线路时通时断的问题

  网络管理包括对硬件、软件和人力的使用、综合与协调,以便对网络资源进行监视、测试、配置、分析、评价和控制,这样就能以合理的价格满足网络的一些需求,如实时运行性能、服务质量等。一起跟着小编来学习:如何解决网络线路时通时断的问题,希望这对大家有帮助!  正正就是因为广域网线路涉及本端线路运营商、本端用户、对端线路运营商以
如何解决网络线路时通时断的问题
2024-04-17

如何解决Java中SimpleDateFormat线程不安全的问题

这篇文章将为大家详细讲解有关如何解决Java中SimpleDateFormat线程不安全的问题,小编觉得挺实用的,因此分享给大家做个参考,希望大家阅读完这篇文章后可以有所收获。1.什么是线程不安全?线程不安全也叫非线程安全,是指多线程执行中
2023-06-15

Java项目中的线程安全问题如何解决

这篇文章给大家介绍Java项目中的线程安全问题如何解决,内容非常详细,感兴趣的小伙伴们可以参考借鉴,希望对大家能有所帮助。解决方案如下:public class Demo_5 { public static void main(String
2023-05-31

如何解析Java线程池在使用中的问题

本篇文章为大家展示了如何解析Java线程池在使用中的问题,内容简明扼要并且容易理解,绝对能使你眼前一亮,通过这篇文章的详细介绍希望你能有所收获。Java线程池需要我们不断的学习,其实我们在使用的时候还是有不少问题需要我们解决。我们实现了一个
2023-06-17

如何处理PHP开发中的多线程和并发问题

一、引言随着互联网的迅速发展,Web应用程序的性能和并发处理是一个至关重要的问题。特别是在PHP开发中,由于PHP是一种解释型语言,其自身的单线程特性导致其并发处理能力有限。然而,在某些场景下,我们仍然需要实现多线程和并发处理来提升Web应
2023-10-21

如何解决 C++ 多线程编程中常见的死锁问题?

如何解决 c++++ 多线程编程中的常见死锁问题?避免死锁的技术:加锁顺序:始终以相同的顺序获取锁。死锁检测:使用算法检测并解决死锁。超时:为锁设置超时值,防止线程无限期等待。优先级反转:分配不同的优先级,减少死锁可能性。如何解决 C++
如何解决 C++ 多线程编程中常见的死锁问题?
2024-05-13

java多线程并发问题如何解决

在Java中,可以使用以下方法来解决多线程并发问题:1. 使用synchronized关键字:可以通过在方法或代码块前加上synchronized关键字来实现同步,确保同一时间只有一个线程可以访问被同步的代码块或方法。2. 使用Lock接口
2023-09-27

redis单线程并发问题如何解决

Redis是一个单线程的内存数据库,它使用了事件驱动的模型,通过将请求放入一个队列中顺序执行来实现并发处理。但是,在高并发情况下,可能会出现性能瓶颈。要解决Redis的单线程并发问题,可以考虑以下几个方面:1. 水平扩展:通过使用Redis
2023-09-11

python中如何处理线性规划问题

这篇文章主要为大家展示了“python中如何处理线性规划问题”,内容简而易懂,条理清晰,希望能够帮助大家解决疑惑,下面让小编带领大家一起研究并学习一下“python中如何处理线性规划问题”这篇文章吧。说明1、问题定义,确定决策变量、目标函数
2023-06-20

如何在Java中切断线程

如何在Java中切断线程?很多新手对此不是很清楚,为了帮助大家解决这个难题,下面小编将为大家详细讲解,有这方面需求的人可以来学习下,希望你能有所收获。使用interrupt()切断线程 当一个线程运行时,另一个线程可以调用对应的Thr
2023-05-31

如何解决Win7下ADSL自动断线的问题方法是什么

Windows7下ADSL自动断线的问题及解js决方法 在 Windows7 中,为什么 ADSL 闲置一段时间就会自动断线呢?在其它软硬件工作正常的情况下,出现这种问题,多半是因为启用了闲置自动断线设定。只要关闭这项功能,问题就能解决了。
2023-05-25

Android中的多线程问题

目录一:问题的提出二:使用Handler处理多线程问题三:使用AsyncTask(异步任务)处理多线程问题 一:问题的提出 Android用户界面是与用户交互的接口,对于用户的操作,Android迅速响应用户的输入是一个重要目标。如果Act
2022-06-06

如何解决mybatis的if判断integer问题

这篇文章主要为大家展示了“如何解决mybatis的if判断integer问题”,内容简而易懂,条理清晰,希望能够帮助大家解决疑惑,下面让小编带领大家一起研究并学习一下“如何解决mybatis的if判断integer问题”这篇文章吧。if判断
2023-06-29

C#开发中如何处理线程同步和并发访问问题

C#开发中如何处理线程同步和并发访问问题,需要具体代码示例在C#开发中,线程同步和并发访问问题是一个常见的挑战。由于多个线程可以同时访问和操作共享数据,可能会出现竞态条件和数据不一致的问题。为了解决这些问题,我们可以使用各种同步机制和并发控
2023-10-22

编程热搜

目录