• 用interrupt()中断Java线程


    最近在学习Java线程相关的东西,和大家分享一下,有错误之处欢迎大家指正. 

    假如我们有一个任务如下,交给一个Java线程来执行,如何才能保证调用interrupt()来中断它呢? 
    Java代码  收藏代码
    1. class ATask implements Runnable{  
    2.   
    3.     private double d = 0.0;  
    4.       
    5.     public void run() {  
    6.         //死循环执行打印"I am running!" 和做消耗时间的浮点计算  
    7.         while (true) {  
    8.             System.out.println("I am running!");  
    9.               
    10.             for (int i = 0; i < 900000; i++) {  
    11.                 d =  d + (Math.PI + Math.E) / d;  
    12.             }  
    13.             //给线程调度器可以切换到其它进程的信号  
    14.             Thread.yield();  
    15.         }  
    16.     }  
    17. }  
    18.   
    19. public class InterruptTaskTest {  
    20.       
    21.     public static void main(String[] args) throws Exception{  
    22.         //将任务交给一个线程执行  
    23.         Thread t = new Thread(new ATask());  
    24.         t.start();  
    25.           
    26.         //运行一断时间中断线程  
    27.         Thread.sleep(100);  
    28.         System.out.println("****************************");  
    29.         System.out.println("Interrupted Thread!");  
    30.         System.out.println("****************************");  
    31.         t.interrupt();  
    32.     }  
    33. }   


    运行这个程序,我们发现调用interrupt()后,程序仍在运行,如果不强制结束,程序将一直运行下去,如下所示: 
    Java代码  收藏代码
    1. ......  
    2. I am running!  
    3. I am running!  
    4. I am running!  
    5. I am running!  
    6. ****************************  
    7. Interrupted Thread!  
    8. ****************************  
    9. I am running!  
    10. I am running!  
    11. I am running!  
    12. I am running!  
    13. I am running!  
    14. ....  

    虽然中断发生了,但线程仍然在进行,离开线程有两种常用的方法: 
    抛出InterruptedException和用Thread.interrupted()检查是否发生中断,下面分别看一下这两种方法: 
    1.在阻塞操作时如Thread.sleep()时被中断会抛出InterruptedException(注意,进行不能中断的IO操作而阻塞和要获得对象的锁调用对象的synchronized方法而阻塞时不会抛出InterruptedException) 
    Java代码  收藏代码
    1. class ATask implements Runnable{  
    2.   
    3.     private double d = 0.0;  
    4.       
    5.     public void run() {  
    6.         //死循环执行打印"I am running!" 和做消耗时间的浮点计算  
    7.         try {  
    8.             while (true) {  
    9.                 System.out.println("I am running!");  
    10.                   
    11.                 for (int i = 0; i < 900000; i++) {  
    12.                     d =  d + (Math.PI + Math.E) / d;  
    13.                 }  
    14.                 //休眠一断时间,中断时会抛出InterruptedException  
    15.                 Thread.sleep(50);  
    16.             }  
    17.         } catch (InterruptedException e) {  
    18.             System.out.println("ATask.run() interrupted!");  
    19.         }  
    20.     }  
    21. }  

    程序运行结果如下: 
    Java代码  收藏代码
    1. I am running!  
    2. I am running!  
    3. ****************************  
    4. Interrupted Thread!  
    5. ****************************  
    6. ATask.run() interrupted!  

    可以看到中断任务时让任务抛出InterruptedException来离开任务. 

    2.Thread.interrupted()检查是否发生中断.Thread.interrupted()能告诉你线程是否发生中断,并将清除中断状态标记,所以程序不会两次通知你线程发生了中断. 
    Java代码  收藏代码
    1. class ATask implements Runnable{  
    2.   
    3.     private double d = 0.0;  
    4.       
    5.     public void run() {  
    6.           
    7.         //检查程序是否发生中断  
    8.         while (!Thread.interrupted()) {  
    9.             System.out.println("I am running!");  
    10.   
    11.             for (int i = 0; i < 900000; i++) {  
    12.                 d = d + (Math.PI + Math.E) / d;  
    13.             }  
    14.         }  
    15.   
    16.         System.out.println("ATask.run() interrupted!");  
    17.     }  
    18. }  

    程序运行结果如下: 
    Java代码  收藏代码
    1. I am running!  
    2. I am running!  
    3. I am running!  
    4. I am running!  
    5. I am running!  
    6. I am running!  
    7. I am running!  
    8. ****************************  
    9. Interrupted Thread!  
    10. ****************************  
    11. ATask.run() interrupted!  


    我们可结合使用两种方法来达到可以通过interrupt()中断线程.请看下面例子: 
    Java代码  收藏代码
    1. class ATask implements Runnable{  
    2.   
    3.     private double d = 0.0;  
    4.       
    5.     public void run() {  
    6.           
    7.         try {  
    8.         //检查程序是否发生中断  
    9.         while (!Thread.interrupted()) {  
    10.             System.out.println("I am running!");  
    11.             //point1 before sleep  
    12.             Thread.sleep(20);  
    13.             //point2 after sleep  
    14.             System.out.println("Calculating");  
    15.             for (int i = 0; i < 900000; i++) {  
    16.                 d = d + (Math.PI + Math.E) / d;  
    17.             }  
    18.         }  
    19.           
    20.         } catch (InterruptedException e) {  
    21.             System.out.println("Exiting by Exception");  
    22.         }  
    23.           
    24.         System.out.println("ATask.run() interrupted!");  
    25.     }  
    26. }  

    在point1之前处point2之后发生中断会产生两种不同的结果,可以通过修改InterruptTaskTest main()里的Thread.sleep()的时间来达到在point1之前产生中断或在point2之后产生中断. 
    如果在point1之前发生中断,程序会在调用Thread.sleep()时抛出InterruptedException从而结束线程.这和在Thread.sleep()时被中断是一样的效果.程序运行结果可能如下: 
    Java代码  收藏代码
    1. I am running!  
    2. Calculating  
    3. I am running!  
    4. Calculating  
    5. I am running!  
    6. Calculating  
    7. I am running!  
    8. ****************************  
    9. Interrupted Thread!  
    10. ****************************  
    11. Exiting by Exception  
    12. ATask.run() interrupted!  

    如果在point2之后发生中断,线程会继续执行到下一次while判断中断状态时.程序运行结果可能如下: 
    Java代码  收藏代码
    1. I am running!  
    2. Calculating  
    3. I am running!  
    4. Calculating  
    5. I am running!  
    6. Calculating  
    7. ****************************  
    8. Interrupted Thread!  
    9. ****************************  
    10. ATask.run() interrupted!  

    Java多线程中,线程的状态有 NEW, Runnable, Blocked, Waiting, Timed_Waiting, Terminated. 这是java虚拟机下的线程状态,与操作系统下的线程状态略有不同。线程状态以枚举类型定义在Thread.State中,并且当前线程可以通过getState()方法获取当前线程的状态。Runnable其实可以有两种状态,一种是获得了cpu,这在运行,这里把它表示为Running,另一种在队列中,等待调度。

    这些状态之间的转化关系可以通过下面的转化图表示:

    有些过程没有写,不然太乱了。

    这里重点说一下stop()以及interrupt。

    对于stop()方法,直接终止线程,释放线程所获的资源,但是在释放过程中会造成对象状态不一致,从而使程序进入未知的境地,已经很久不推荐使用了。可以通过设定标志位来检测线程终止状态,使线程自动终止。简略实现如下:

    boolean stop = false;

    public void run(){

            while(!stop){

            }

    }

    在需要终止线程的地方把stop设置为true即可。

    interrupt方法好多初学者会感到困惑,发现一些情况下并不能终止线程。在Java API中有对此详细的说明:

    如果线程在调用 Object 类的 wait()wait(long) 或 wait(long, int) 方法,或者该类的join()join(long)join(long, int)sleep(long) 或 sleep(long, int) 方法过程中受阻,则其中断状态将被清除,它还将收到一个 InterruptedException

    如果该线程在可中断的通道上的 I/O 操作中受阻,则该通道将被关闭,该线程的中断状态将被设置并且该线程将收到一个 ClosedByInterruptException

    因此,可以看出,interrupt之后作用到wait() join() 已经sleep()上。 2014阿里巴巴笔试题的附加题中对这个知识进行了终点考核,其代码如下:

    [java] view plain copy
     
    1. public class TestInterrupt {  
    2.   
    3.     /** 
    4.      * @param args 
    5.      */  
    6.     public static void main(String[] args) {  
    7.         // TODO Auto-generated method stub  
    8.           
    9.         Thread thread1 = new Thread(){  
    10.             public void run(){  
    11.                 try{  
    12.                     long time = System.currentTimeMillis();  
    13.                     while(System.currentTimeMillis()-time<2000){  
    14.                     }                     
    15.                     System.out.println("A1");  
    16.                 }  
    17.                 catch(Exception e)  
    18.                 {  
    19.                     System.out.println("B1");  
    20.                 }                 
    21.             }  
    22.         };  
    23.         thread1.start();  
    24.         thread1.interrupt();  
    25.           
    26.         //在线程sleep状态下进行中断  
    27.         Thread thread2 = new Thread(){  
    28.             public void run(){  
    29.                 try {  
    30.                     this.sleep(2000);  
    31.                     System.out.println("A2");  
    32.                 } catch (Exception e) {  
    33.                     // TODO Auto-generated catch block  
    34.                     System.out.println("B2");  
    35.                 }  
    36.             }  
    37.               
    38.         };  
    39.           
    40.         thread2.start();  
    41.         thread2.interrupt();  
    42.           
    43.         //在线程wait状态下进行中断,其中wait()没有在同步块中  
    44.         Thread thread3 = new Thread(){  
    45.             public void run(){  
    46.                 try {  
    47.                     this.wait(2000);  
    48.                     System.out.println("A3");  
    49.                 } catch (Exception e) {  
    50.                     // TODO Auto-generated catch block  
    51.                     System.out.println("B3");  
    52.                 }  
    53.             }  
    54.               
    55.         };  
    56.           
    57.         thread3.start();  
    58.         thread3.interrupt();  
    59.           
    60.         //在线程wait状态下进行中断,其中wait()在同步块中  
    61.         Thread thread4 = new Thread(){  
    62.             public void run(){  
    63.                 try {  
    64.                     synchronized(this){  
    65.                         this.wait(2000);  
    66.                         System.out.println("A4");}  
    67.                 } catch (Exception e) {  
    68.                     // TODO Auto-generated catch block  
    69.                     System.out.println("B4");  
    70.                 }  
    71.             }  
    72.               
    73.         };  
    74.           
    75.         thread4.start();  
    76.         thread4.interrupt();  
    77.       
    78.           
    79.         try{  
    80.             thread4.start();  
    81.             System.out.println("A5");  
    82.         }  
    83.         catch(Exception e)  
    84.         {  
    85.             System.out.println("B5");  
    86.             System.out.println(e.toString());  
    87.         }  
    88.           
    89.           
    90.     }  
    91.   
    92. }  

    我们可以运行,发下运行结果如下(不考虑执行顺序):

    A1 

    B2

    B3

    B4

    B5 //这个是由于一个thread,不能start两次引起的。。和interrupt无关

  • 相关阅读:
    第四章5
    第四章4
    第四章3
    第四章2
    第四章1
    第四章例4-8
    第四章例4-7
    第四章例4-6
    第四章例4-5
    第四章例4-4
  • 原文地址:https://www.cnblogs.com/diegodu/p/6362565.html
Copyright © 2020-2023  润新知