zoukankan      html  css  js  c++  java
  • java 多线程6: 中断机制 优雅的终止java线程




    使用 interrupt() 和 interrupted() 判断来终止线程


    1. public class Run {
    2. public static void main(String[] args) {
    3. try {
    4. MyThread thread = new MyThread();
    5. thread.start();
    6. Thread.sleep(2000);
    7. thread.interrupt();//请求中断MyThread线程
    8. } catch (InterruptedException e) {
    9. System.out.println("main catch");
    10. e.printStackTrace();
    11. }
    12. System.out.println("end!");
    13. }
    14. }

    main线程睡眠2000ms后,执行第8行中断MyThread线程。

    1. public class MyThread extends Thread {
    2. @Override
    3. public void run() {
    4. super.run();
    5. for (int i = 0; i < 500000; i++) {
    6. if (this.interrupted()) {
    7. System.out.println("should be stopped and exit");
    8. break;
    9. }
    10. System.out.println("i=" + (i + 1));
    11. }
    12. System.out.println("this line is also executed. thread does not stopped");//尽管线程被中断,但并没有结束运行。这行代码还是会被执行
    13. }
    14. }

    当MyThread获得CPU执行时,第6行的 if 测试中,检测到中断标识被设置。即MyThread线程检测到了main线程想要中断它的 请求。

    大多数情况下,MyThread检测到了中断请求,对该中断的响应是:退出执行(或者说是结束执行)。

    但是,上面第5至8行for循环,是执行break语句跳出for循环。但是,线程并没有结束,它只是跳出了for循环而已,它还会继续执行第12行的代码....

    因此,我们的问题是,当收到了中断请求后,如何结束该线程呢?

    一种可行的方法是使用 return 语句 而不是 break语句。。。。。哈哈。。。

    不过使用return 没有抛异常那么好,不能将事件传播

    优雅的解决
    抛异常方法 抛出InterruptedException异常

    1. public class MyThread extends Thread {
    2. @Override
    3. public void run() {
    4. super.run();
    5. try{
    6. for (int i = 0; i < 500000; i++) {
    7. if (this.interrupted()) {
    8. System.out.println("should be stopped and exit");
    9. throw new InterruptedException();
    10. }
    11. System.out.println("i=" + (i + 1));
    12. }
    13. System.out.println("this line cannot be executed. cause thread throws exception");//这行语句不会被执行!!!
    14. }catch(InterruptedException e){
    15. System.out.println("catch interrupted exception");
    16. e.printStackTrace();
    17. }
    18. }
    19. }

    当MyThread线程检测到中断标识为true后,在第9行抛出InterruptedException异常。这样,该线程就不能再执行其他的正常语句了(如,第13行语句不会执行)。


    因此,上面就是一个采用抛出异常的方式来结束线程的示例。尽管该示例的实用性不大。原因是我们 生吞了中断。

    在第14行,我们直接catch了异常,然后打印输出了一下而已,调用栈中的更高层的代码是无法获得关于该异常的信息的。

    第16行的e.printStackTrace()作用就相当于

    在这里是生吞了异常  由于
    this.interrupted()在第一次调用后清楚中断状态为false(注意这里是调用
    this.interrupted()这个方法会清楚中断状态,而不是抛出异常会清除中断状态,而isInterrupted()这个不会清除中断状态,这两种区别在
    1.仅仅记录 InterruptedException 也不是明智的做法,因为等到人来读取日志的时候,再来对它作出处理就为时已晚了。
    有时候抛出 InterruptedException 并不合适,例如当由 Runnable 定义的任务调用一个可中断的方法时,就是如此。在这种情况下,不能重新抛出 InterruptedException,但是您也不想什么都不做。当一个阻塞方法检测到中断并抛出 InterruptedException 时,它清除中断状态。如果捕捉到 InterruptedException 但是不能重新抛出它,那么应该保留中断发生的证据,以便调用栈中更高层的代码能知道中断,并对中断作出响应。该任务可以通过调用 interrupt() 以 “重新中断” 当前线程来完成
    2.因为,run方法是实现的Runnable接口中的方法。不能像下面这样定义,也即上面所说的:“不能重新抛出InterruptedException”。
            @Override
            public void run() throws InterruptedException{//这是错误的
              //do something...

     

    代码改良 

    1. public class MyThread extends Thread {
    2. @Override
    3. public void run() {
    4. super.run();
    5. try{
    6. for (int i = 0; i < 500000; i++) {
    7. if (this.interrupted()) {
    8. System.out.println("should be stopped and exit");
    9. throw new InterruptedException();
    10. }
    11. System.out.println("i=" + (i + 1));
    12. }
    13. System.out.println("this line cannot be executed. cause thread throws exception");
    14. }catch(InterruptedException e){
    15. /**这样处理不好
    16. * System.out.println("catch interrupted exception");
    17. * e.printStackTrace();
    18. */
    19. Thread.currentThread().interrupt();//这样处理比较好
    20. }
    21. }
    22. }

    这样,就由 生吞异常 变成了 将 异常事件 进一步扩散了。 保留了中断的证据


    ps 
    对于可取消的阻塞状态中的线程, 比如等待在这些函数上的线程, Thread.sleep(), Object.wait(), Thread.join(), 这个线程收到中断信号interrupt()后, 会抛出InterruptedException。就不需要手动抛异常法了,只需要在捕获异常块再次标记中断即可



  • 相关阅读:
    JavaScript中的__proto__
    移动前端调试页面–weinre
    nodo合并多个mp3文件
    enctype和Content-type有什么关系
    vscode 实用的插件
    前端跨域问题及解决方案
    小小的js
    如何使用eslint
    RN记录
    numpy的索引
  • 原文地址:https://www.cnblogs.com/signheart/p/8bb7a43d9def66f6369ecfcfc56bffde.html
Copyright © 2011-2022 走看看