暂无图片
暂无图片
暂无图片
暂无图片
暂无图片

掌握并发控制的“急刹车”艺术!

追梦Java 2024-05-27
71



当一个线程运行时,另外一个线程可以直接通过interrupt方法对其设置中断标志位。


判断线程是否中断的2个方法:

     // 判断目标线程是否被中断,不会清除中断标记。
    Thread.currentThread().isInterrupted()
      // 判断目标线程是否被中断,会清除中断标记
      Thread.interrupted()


      示例1:判断目标线程是否被中断,不会清除中断标记

        public class Task2 implements Runnable {
        @Override
        public void run() {
        System.out.println("线程的run方法开始执行");
        // 判断线程是否被中断,不会清除中断标记
        if (Thread.currentThread().isInterrupted()) {
        System.out.println("线程被中断");
        }
        if (!Thread.currentThread().isInterrupted()) {
        // 因为上面的Thread.currentThread().isInterrupted()不会清除中断标记
        // 因此线程保留了中断标记,所以该循环不会执行,程序不会输出1-3的数字
        for (int i = 0; i < 3; i++) {
        System.out.println("线程运行,i=" + i);
        }
        }
        System.out.println("线程的run方法执行结束");
        }
        }


        运行上面的测试类Task2InterruptTest,


        程序运行结果:
        线程的run方法开始执行
        线程被中断
        线程的run方法执行结束

        以上的程序说明,Thread.currentThread().isInterrupted()不会清除中断标记,因此线程保留了中断标记,所以该循环不会执行,程序不会输出1-3的数字。


        示例2:判断目标线程是否被中断,清除中断标记

          public class Task3 implements Runnable {
          @Override
          public void run() {
          System.out.println("线程的run方法开始执行");
          // 判断线程是否被中断,会清除中断标记
          if (Thread.interrupted()) {
          System.out.println("线程被中断");
          }
          if (!Thread.currentThread().isInterrupted()) {
          // 因为上面的Thread.interrupted()会清除中断标记
          // 因此线程的中断标记没有了,线程继续执行,程序会输出1-3的数字
          for (int i = 0; i < 3; i++) {
          System.out.println("线程运行,i=" + i);
          }
          }
          System.out.println("线程的run方法执行结束");
          }
          }


          // 测试类
          public class Task3InterruptTest {
          public static void main(String[] args) {
          Task3 task = new Task3();
          Thread thread = new Thread(task);
          thread.start();
          thread.interrupt(); // 中断thread线程的执行
          }
          }


          程序运行结果:
          线程的run方法开始执行
          线程被中断
          线程运行,i=0
          线程运行,i=1
          线程运行,i=2
          线程的run方法执行结束

          以上的程序说明,Thread.interrupted()会清除中断标记,thread线程没有了中断标记,因此Thread.currentThread().isInterrupted()的结果为false,所以线程继续执行,程序会输出1-3的数字。


          下面我们来看一下如果处于阻塞状态(调用了sleep、join等方法)的线程,被执行了中断操作,会有什么样的结果。


          答案很明显,处于阻塞状态下的线程被执行了中断操作,会抛出中断异常InterruptedException。


          示例3:处于阻塞状态的线程被执行中断操作的结果演示

            public class Task4 implements Runnable {
            @Override
            public void run() {
            System.out.println("线程的run方法开始执行");
            try {
            Thread.sleep(5000); // 线程休眠5秒
            System.out.println("线程完成5秒钟的休眠");
            } catch (InterruptedException e) {
            e.printStackTrace();
            }
            System.out.println("线程的run方法执行结束");
            }
            }


            // 测试类
            public class Task4InterruptTest {
            public static void main(String[] args) {
            Task4 task = new Task4();
            Thread thread = new Thread(task);
            thread.start();
            try {
            Thread.sleep(2000); // 主线程休眠2秒
            } catch (InterruptedException e) {
            e.printStackTrace();
            }
            thread.interrupt(); // 中断thread线程的执行
            }
            }


            程序运行结果:
            线程的run方法开始执行
            java.lang.InterruptedException: sleep interrupted
            at java.lang.Thread.sleep(Native Method)
            at testThread.day3.Task4.run(Task4.java:8)
            at java.lang.Thread.run(Unknown Source)
            线程的run方法执行结束

            通过上面的程序可以看出,处于阻塞状态下的线程被执行了中断操作,会抛出中断异常InterruptedException,但是thread线程在捕获到异常后,输出了“线程的run方法执行结束”的文字,说明thread线程在接收到中断指令后,并没有中断线程的执行,而是继续向下执行。


            通过以上的程序示例,我们可以得出一个结论,那就是线程在执行了中断指令后,其实是给线程发了一个中断信号,线程被打上中断标记,如果线程没有对中断标记进行判断,做相应的处理,那么线程默认会继续执行,直到线程操作结束。


            那么,问题来了,处于阻塞状态的线程被执行中断指令后,如何做到线程的中断呢,请看以下的代码。


            示例4:处于阻塞状态的线程被执行中断指令后,立即把线程中断

              public class Task5 implements Runnable {
              @Override
              public void run() {
              System.out.println("线程的run方法开始执行");
              try {
              Thread.sleep(5000); // 线程休眠5秒
              System.out.println("线程完成5秒钟的休眠");
              } catch (InterruptedException e) {
              // 在catch块里进行处理,再次调用interrupt方法,线程是否会中断执行呢?
              System.out.println("线程被中断");
              Thread.currentThread().interrupt();
              }
              for (int i = 0; i < 3; i++) {
              System.out.println(i);
              }
              System.out.println("线程的run方法执行结束");
              }
              }


              // 测试类
              public class Task5InterruptTest {
              public static void main(String[] args) {
              Task5 task = new Task5();
              Thread thread = new Thread(task);
              thread.start();
              try {
              Thread.sleep(2000); // 主线程休眠2秒
              } catch (InterruptedException e) {
              e.printStackTrace();
              }
              thread.interrupt(); // 中断thread线程的执行
              }
              }


              程序运行结果
              线程的run方法开始执行
              线程被中断
              0
              1
              2
              线程的run方法执行结束

              通过上面的程序,大家会感到奇怪,明明已经在catch块里,又调用了Thread.currentThread().interrupt()方法,但是线程还是没有中断,继续往下执行。


              在这里再一次和大家要强调说明的就是,调用线程的interrupt()方法,不是说线程就不执行了,而是向线程发出了中断信号,线程被打上中断标记,如果想让线程中断,必须在run方法里对中断信号进行响应,让程序return返回到被调用处,才能使线程真正的中断。


              示例5:正确的让线程中断的例子

                public class Task6 implements Runnable {
                @Override
                public void run() {
                System.out.println("线程的run方法开始执行");
                try {
                Thread.sleep(5000); // 线程休眠5秒
                System.out.println("线程完成5秒钟的休眠");
                } catch (InterruptedException e) {
                // 在catch块里进行处理,让程序返回被调用处
                System.out.println("线程被中断");
                return;
                }
                for (int i = 0; i < 3; i++) {
                System.out.println(i);
                }
                System.out.println("线程的run方法执行结束");
                }
                }


                // 测试类
                public class Task6InterruptTest {
                public static void main(String[] args) {
                Task6 task = new Task6();
                Thread thread = new Thread(task);
                thread.start();
                try {
                Thread.sleep(2000); // 主线程休眠2秒
                } catch (InterruptedException e) {
                e.printStackTrace();
                }
                thread.interrupt(); // 中断thread线程的执行
                }
                }


                程序运行结果:
                线程的run方法开始执行
                线程被中断

                通过上面的程序,可以看出,使用return可以做到中断线程。


                线程的中断其实是为了优雅的停止线程的运行,为了不使用stop方法而设置的。因为JDK不推荐使用stop方法进行线程的停止,因为stop方法会释放锁并强制终止线程,会造成执行一半的线程终止,带来数据的不一致性。

                文章转载自追梦Java,如果涉嫌侵权,请发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

                评论