• Java多线程之interrupt()的深度研究


      近期学习Java多线程的中断机制,网上的帖子说得很浅,并没深究其原理。看了Java源码,对Java的中断机制有了略深入的理解,在这篇文章中向感兴趣的网友分享下。这篇文章主要通过一个典型例子对中断机制进行剖析。

      一:一些概念和重要方法

      interrupt status(中断状态):请记住这个术语,中断机制就是围绕着这个字段来工作的。在Java源码中代表中断状态的字段是:private volatile Interruptible blocker;对“Interruptible”这个类不需要深入分析,对于“blocker”变量有以下几个操作。

      1.默认blocker=null; ®1

      2.调用方法“interrupt0();”将会导致“该线程的中断状态将被设置(JDK文档中术语)”。®2

      3.再次调用“interrupt0();”将会导致“其中断状态将被清除(同JDK文档中术语)”®3

      注:这三点很重要,接下来文章中会用来®1®2®3代替。

    明白了第一点来看下文档中对于中断线程相关方法的描述。

      1.public void interrupt();

        中断线程。如果线程在调用 Object 类的 wait()wait(long)wait(long, int) 方法,或者该类的 join()join(long)join(long, int)sleep(long)sleep(long, int) 方法

      过程中受阻,则其中断状态将被清除,它还将收到一个 InterruptedException。 

      2.public static boolean interrupted();

        测试当前线程是否已经中断。线程的中断状态 由该方法清除。线程中断被忽略,因为在中断时不处于活动状态的线程将由此返回 false 的方法反映出来。

          返回:
        如果当前线程已经中断,则返回 true;否则返回 false
          另请参见:
    isInterrupted()

      3.public boolean isInterrupted();

        测试线程是否已经中断。线程的中断状态 不受该方法的影响。线程中断被忽略,因为在中断时不处于活动状态的线程将由此返回 false 的方法反映出来。

      返回:如果该线程已经中断,则返回 true;否则返回 false

      另请参见:interrupted()

      <!--来自JDK API文档-->

        以上三段中关于线程的中断状态 由该方法清除的描述,在源码层面就是®3调用。

     接下来说一下"interrupted()"和"isInterrupted()"两个方法的相同点和不同点。在这之前看一下源码中两个方法的代码,如下:

     1 public static boolean interrupted() {
     2     return currentThread().isInterrupted(true);
     3     }
     4 public boolean isInterrupted() {
     5     return isInterrupted(false);
     6     }
     7  /**
     8      * Tests if some Thread has been interrupted.  The interrupted state
     9      * is reset or not based on the value of ClearInterrupted that is
    10      * passed.
    11      */
    12 private native boolean isInterrupted(boolean ClearInterrupted);

      相同点都是判断线程的interrupt status是否被设置,若被设置返回true,否则返回false.区别有两点:一:前者是static方法,调用者是current thread,而后者是普通方法,调用者是this current.二:它们其实都调用了Java中的一个native方法isInterrupted(boolean ClearInterrupted); 不同的是前者传入了参数true,后者传入了false.意义就是:前者将清除线程的interrupt state(®3),调用后者线程的interrupt state不受影响。

    二:例子。

      接下来看一个例子,这个例子说明了两个问题。1.调用interrupt()方法并不会中断一个正在运行的线程.2.若调用sleep()而使线程处于阻塞状态,这时调用interrupt()方法,会抛出InterruptedException,从而使线程提前结束阻塞状态,退出阻塞代码。如下:

     1 package interrupt;
     2 
     3 public class Main {
     4     /**
     5      * @param args
     6      */
     7     public static void main(String[] args) {
     8         Main main = new Main();
     9         Thread t = new Thread(main.runnable);
    10         System.out.println("mainmainmain");
    11         t.start();
    12         try {
    13             Thread.sleep(2000);
    14         } catch (InterruptedException e) {
    15             // TODO Auto-generated catch block
    16             e.printStackTrace();
    17         }
    18         t.interrupt();
    19     }
    20 
    21     Runnable runnable = new Runnable() {
    22         @Override
    23         public void run() {
    24             int i = 0;
    25             try {
    26                 while (i < 1000) {
    27                     Thread.sleep(500);
    28                     System.out.println(i++);
    29                 }
    30             } catch (InterruptedException e) {
    31                 e.printStackTrace();
    32             }
    33         }
    34     };
    35 }

    运行结果:

    1 mainmainmain
    2 0
    3 1
    4 2
    5 java.lang.InterruptedException: sleep interrupted
    6     at java.lang.Thread.sleep(Native Method)
    7     at interrupt.Main$1.run(Main.java:27)
    8     at java.lang.Thread.run(Thread.java:619)

    三:分析下例子中的中断机制

     1.为什么调用interrupt()并不能中断线程?

     1 public void interrupt() {
     2     if (this != Thread.currentThread())
     3         checkAccess();
     4 
     5     synchronized (blockerLock) {
     6         Interruptible b = blocker;
     7         if (b != null) {
     8         interrupt0();        // Just to set the interrupt flag
     9         b.interrupt();
    10         return;
    11         }
    12     }
    13     interrupt0();
    14     }

    如上是Java源码中的代码,由此我们看出问题的答案。线程的blocker字段(也就是interrupt status)默认是null(®1)。调用interrupt()方法时,只是运行了®2,并没有进入if语句,所以没调用真正执行中断的代码b.interrupt().

    2.若调用sleep()而使线程处于阻塞状态,这时调用interrupt()方法,会抛出InterruptedException,从而使线程提前结束阻塞状态,退出阻塞代码。为什么?

    由上图可看出例子中30行代码铺好的异常其实是interrupt()抛出的,而不是sleep()抛出的。

    欢迎交流!

    Author:Andy Zhai

    2014-01-12  17:54:39

     

     

     

     

  • 相关阅读:
    CLR(Common Language Runtime)
    六个经典的英语面试问题
    XML基本知识(三)
    vc++中各种字符串(转载)
    winform窗体间传值
    jQuery实现按比例缩放图片
    .net中几个名词解释
    XML Schema 定义
    C#中TreeView组件使用方法初步
    微软电话面试题
  • 原文地址:https://www.cnblogs.com/carmanloneliness/p/3516405.html
Copyright © 2020-2023  润新知