1.中断概述
      在多线程编程中经常会遇到需要中止线程的情况,比如启动多个线程去数据库中搜索,如果有一个线程返回了结果,其他线程就可以取消了。

中断线程的三个相差函数
            1.通过成员方法Thread.interrupt()来设置中断状态为true
             2.通过成员方法Thread.isInterrupted()来获取中断状态
             3.通过静态方法Thread.interrupted()来获取中断状态,并且清除中断状态(当然获取的是清除之前的值),也就是说连续两次调用此方法,第二次一定会返回false。

对正在运行的线程调用 interrupt(),并不会使线程停止运行,而只是 让线程暂停一会,详见《 例1:中断但不停止线程的运行 》。 因为 Thread.interrupt() 对正在运行的线程是不起作用的,只有对阻塞的线程有效 。

离开线程有三种常用的方法:
1.在阻塞操作时如Thread.sleep()时被中断会抛出InterruptedException
        Thread.interrupt() 方法实际上只是设置了一个中断状态,当该线程由于下列原因而受阻时,这个中断状态就起作用了:
      (1)如果线程在调用 Object 类的 wait()、wait(long) 或 wait(long, int) 方法,或者该类的 join()、join(long)、join(long, int)、sleep(long) 或 sleep(long, int) 方法过程中受阻,则其 中断状态将被清除 ,它还将收到一个InterruptedException异常。这个时候,我们可以通过捕获 InterruptedException异常来终止线程的执行,具体可以通过return等退出或改变共享变量的值使其退出。
      详见《 例2:线程在sleep时调用interrupt 》

      (2)如果该线程在可 中断的通道上的 I/O 操作 中受阻,则该通道将被关闭,该线程的中断状态将被设置并且该线程将收到一个 ClosedByInterruptException,而不是InterruptedException 异常。
      
      (3)如果使用Java1.0之前就存在的 传统的I/O操作 ,并且线程处于阻塞状态,Thread.interrupt()将不起作用,线程并不能退出阻塞状态。
               例如对于socket,通过调用阻塞该线程的套接字的close()方法。如果线程被I/O操作阻塞,该线程将接收到一个 SocketException异常 ,这与使用interrupt()方法引起一个InterruptedException异常被抛出非常相似。
      详见《 例6:通过SocketException异常中断阻塞线程 》

2.Thread.interrupted()检查是否发生中断
      对于正在运行的线程,如果调用thread.interrupt()。可以通过 T hread.interrupted()能告诉你线程是否发生中断,并将清除中断状态标记,所以程序不会两次通知你线程发生了中断。 
      详见《 例3:通过interrupted中断线程 》

      如果sleep和interrupted检查结合使用,可能会产生两个结果。
      详见《 例4: 通过interrupted和sleep中断线程,停止线程的执行 》

3.使用共享变量控制
      使用共享变量(shared variable)发出信号,告诉线程必须停止正在运行的任务。线程必须周期性的核查这一变量(尤其在冗余操作期间),然后有秩序地中止任务。
      详见《 例5:通过共享变量中断线程,停止线程的执行 》

      这个方法虽然给予线程机会进行必要的清理工作,这在任何一个多线程应用程序中都是绝对需要的。请确认将共享变量定义成volatile 类型或将对它的一切访问封入同步的块/方法(synchronized blocks/methods)中。

      但是,当线程等待某些事件发生而被阻塞,又会发生什么?当然, 如果线程被阻塞,它便不能核查共享变量,也就不能停止。
      他们都可能永久的阻塞线程。即使发生超时,在超时期满之前持续等待也是不可行和不适当的,所以,要使用某种机制使得线程更早地退出被阻塞的状态。

总结
      不存在这样一种机制对所有的情况都适用,但是,根据情况不同却可以使用特定的技术。
      详见《 java线程技术8_线程中断最佳实践 》
      
例1:中断但不停止线程的运行
假设我们想中断一个正在执行的线程。代码 如下

1. /**
2.   * 中断一个正在执行的线程,但是并未实现中断.
3.   * @version V1.0 ,2011-4-15
4.   * @author xiahui
5.   */
6. public class InterruptThread1 extends Thread {
7. private double d = 0.0;
8. public void run() {
9. // 死循环执行打印"I am running!" 和做消耗时间的浮点计算
10. while (true) {
11. System.out.println("I am running!");
12.  
13. for (int i = 0; i < 900000; i++) {
14. = d + (Math.PI + Math.E) / d;
15. }
16. // 给线程调度器可以切换到其它进程的信号
17. Thread.yield();
18. }
19. }
20. public static void main(String[] args) throws Exception {
21. // 将任务交给一个线程执行
22. = new InterruptThread1();
23. .start();
24. // 运行一断时间中断线程
25. Thread.sleep(100);
26. System.out.println("****************************");
27. System.out.println("Interrupted Thread!");
28. System.out.println("****************************");
29. .interrupt();
30. }
31. }


运行结果

1. I am 
2.  I am 
3.  I am 
4. ****************************
5. Interrupted 
6. ****************************
7.  I am 
8.  I am


从结果可以看出,中断的调用并未让线程停止。



例2:线程在sleep时调用interrupt,停止线程的运行

1. /**
2.   * 通过线程sleep时调用Interrupt引发异常,停止线程的运行.
3.   * @version V1.0 ,2011-4-15
4.   * @author xiahui
5.   */
6. public class InterruptThread1 extends Thread {
7. private double d = 0.0;
8.  
9. public void run() {
10. try { 
11. // 死循环执行打印"I am running!" 和做消耗时间的浮点计算
12. while (true) {
13. System.out.println("I am running!");
14.  
15. for (int i = 0; i < 900000; i++) {
16. = d + (Math.PI + Math.E) / d;
17. }
18. //休眠一断时间,中断时会抛出InterruptedException 
19. Thread.sleep(50);
20. }
21. }catch (InterruptedException e) { 
22. System.out.println("InterruptThread1.run() interrupted!");
23. } 
24. }
25.  
26. public static void main(String[] args) throws Exception {
27. // 将任务交给一个线程执行
28. = new InterruptThread1();
29. .start();
30.  
31. // 运行一断时间中断线程
32. Thread.sleep(100);
33. System.out.println("****************************");
34. System.out.println("Interrupted Thread!");
35. System.out.println("****************************");
36. .interrupt();
37. }
38. }


运行结果

1.  I am running!
2.  ****************************
3.  Interrupted Thread!
4.  ****************************
5.  I am running!
6.  ATask.run() interrupted!

例3:通过interrupted中断线程


    1. /**
    2.   * 通过interrupted中断线程,停止线程的执行.
    3.   * 
    4.   * @version V1.0 ,2011-4-15
    5.   * @author xiahui
    6.   */
    7. public class InterruptThread1 extends Thread {
    8. private double d = 0.0;
    9.  
    10. public void run() {
    11. // 检查程序是否发生中断
    12. while (!Thread.interrupted()) {
    13. System.out.println("I am running!");
    14.  
    15. for (int i = 0; i < 900000; i++) {
    16. = d + (Math.PI + Math.E) / d;
    17. }
    18. }
    19. }
    20.  
    21. public static void main(String[] args) throws Exception {
    22. // 将任务交给一个线程执行
    23. = new InterruptThread1();
    24. .start();
    25.  
    26. // 运行一断时间中断线程
    27. Thread.sleep(100);
    28. System.out.println("****************************");
    29. System.out.println("Interrupted Thread!");
    30. System.out.println("****************************");
    31. .interrupt();
    32. }
    33. }


    运行结果

    1.  I am running!
    2.  I am running!
    3.  ****************************
    4.  Interrupted Thread!
    5.  ****************************



    例4: 通过interrupted和sleep中断线程,停止线程的执行

    1. /**
    2.   * 通过interrupted和sleep中断线程,停止线程的执行.
    3.   * 
    4.   * @version V1.0 ,2011-4-15
    5.   * @author xiahui
    6.   */
    7. public class InterruptThread1 extends Thread {
    8. private double d = 0.0;
    9.  
    10. public void run() {
    11. try {
    12. // 检查程序是否发生中断
    13. while (!Thread.interrupted()) {
    14. System.out.println("I am running!");
    15. // before sleep
    16. Thread.sleep(20);
    17. //after sleep
    18. System.out.println("Calculating");
    19. for (int i = 0; i < 900000; i++) {
    20. = d + (Math.PI + Math.E) / d;
    21. }
    22. }
    23.  
    24. } catch (InterruptedException e) {
    25. System.out.println("InterruptThread1.run() Exception!");
    26. }
    27.  
    28. System.out.println("InterruptThread1.run() end!");
    29. }
    30.  
    31. public static void main(String[] args) throws Exception {
    32. // 将任务交给一个线程执行
    33. = new InterruptThread1();
    34. .start();
    35.  
    36. // 运行一断时间中断线程
    37. Thread.sleep(200);
    38. System.out.println("****************************");
    39. System.out.println("Interrupted Thread!");
    40. System.out.println("****************************");
    41. .interrupt();
    42. }
    43. }


    运行结果1

    1.  I am running!
    2.  Calculating
    3.  I am running!
    4.  ****************************
    5.  Interrupted Thread!
    6.  ****************************
    7.  InterruptThread1.run() Exception!
    8.  InterruptThread1.run() end!


    运行结果2



    1.  I am running!
    2.  Calculating
    3.  ****************************
    4.  Interrupted Thread!
    5.  ****************************
    6.  InterruptThread1.run() end!


    如果在睡眠之前产生中断,则调用Thread.sleep()时抛出InterruptedException,结束线程,参见运行结果1


    如果在睡眠之后产生中断,则线程会继续执行到下一次while判断中断状态时,结束线程,参见运行结果2



    例5:通过共享变量中断线程,停止线程的执行

      1. /**
      2.   * 通过共享变量中断线程,停止线程的执行.
      3.   * @version V1.0 ,2011-4-15
      4.   * @author xiahui
      5.   */
      6. public class InterruptThread1 extends Thread {
      7. private double d = 0.0;
      8. volatile boolean stop = false;
      9.      
      10. public void run() {
      11. // 检查程序是否发生中断
      12. while (!stop) {
      13. System.out.println("I am running!");
      14.  
      15. for (int i = 0; i < 900000; i++) {
      16. = d + (Math.PI + Math.E) / d;
      17. }
      18. }
      19. //做一些清理工作
      20. System.out.println( "Thread is exiting under request..." );
      21. }
      22.  
      23. public static void main(String[] args) throws Exception {
      24. // 将任务交给一个线程执行
      25. = new InterruptThread1();
      26. .start();
      27.  
      28. // 运行一断时间中断线程
      29. Thread.sleep(100);
      30. System.out.println( "Asking thread to stop..." );
      31. .stop = true;
      32.  
      33. Thread.sleep(1000 );
      34. System.out.println( "Stopping application..." );
      35. }
      36. }


      例6:通过SocketException异常中断阻塞线程


      1. import java.io.IOException;
      2. import java.net.ServerSocket;
      3. import java.net.Socket;
      4.  
      5. /**
      6.   * 通过SocketException异常中断阻塞线程.
      7.   * @version V1.0 ,2011-4-17
      8.   * @author xiahui
      9.   */
      10. public class InterruptThread2 extends Thread {
      11. volatile boolean stop = false;
      12. volatile ServerSocket socket;
      13.  
      14. public void run() {
      15. try {
      16. socket = new ServerSocket(7856);
      17. } catch (IOException e) {
      18. System.out.println("Could not create the socket...");
      19. return;
      20. }
      21. while (!stop) {
      22. System.out.println("Waiting for connection...");
      23. try {
      24. Socket sock = socket.accept();
      25. } catch (IOException e) {
      26. System.out.println("accept() failed or interrupted...");
      27. }
      28. }
      29. System.out.println("Thread exiting under request...");
      30. }
      31.  
      32. public static void main(String args[]) throws Exception {
      33. thread = new InterruptThread2();
      34. System.out.println("Starting thread...");
      35. thread.start();
      36. Thread.sleep(3000);
      37. System.out.println("Asking thread to stop...");
      38.          
      39. /*由于线程处理阻塞状态,interrupt不产生任何作用*/
      40. //System.out.println( "Interrupting thread..." );
      41. //thread.interrupt();
      42.           
      43. thread.stop = true;
      44. thread.socket.close();
      45. Thread.sleep(3000);
      46. System.out.println("Stopping application...");
      47.  
      48. }
      49. }


      运行结果


      1.  Starting thread...
      2.  Waiting for connection...
      3.  Asking thread to stop...
      4.  accept() failed or interrupted...
      5.  Thread exiting under request...
      6.  Stopping application...