Chinaunix首页 | 论坛 | 博客
  • 博客访问: 3351486
  • 博文数量: 530
  • 博客积分: 13360
  • 博客等级: 上将
  • 技术积分: 5473
  • 用 户 组: 普通用户
  • 注册时间: 2006-07-13 13:32
文章分类

全部博文(530)

文章存档

2017年(1)

2015年(2)

2013年(24)

2012年(20)

2011年(97)

2010年(240)

2009年(117)

2008年(12)

2007年(8)

2006年(9)

分类: Java

2011-04-08 11:42:04

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()。可以通过Thread.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.             for (int i = 0; i < 900000; i++) {
  13.                 d = d + (Math.PI + Math.E) / d;
  14.             }
  15.             // 给线程调度器可以切换到其它进程的信号
  16.             Thread.yield();
  17.         }
  18.     }
  19.     public static void main(String[] args) throws Exception {
  20.         // 将任务交给一个线程执行
  21.         InterruptThread1 t = new InterruptThread1();
  22.         t.start();
  23.         // 运行一断时间中断线程
  24.         Thread.sleep(100);
  25.         System.out.println("****************************");
  26.         System.out.println("Interrupted Thread!");
  27.         System.out.println("****************************");
  28.         t.interrupt();
  29.     }
  30. }
运行结果
  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.     public void run() {
  9.     try {
  10.         // 死循环执行打印"I am running!" 和做消耗时间的浮点计算
  11.         while (true) {
  12.             System.out.println("I am running!");

  13.             for (int i = 0; i < 900000; i++) {
  14.                 d = d + (Math.PI + Math.E) / d;
  15.             }
  16.             //休眠一断时间,中断时会抛出InterruptedException
  17.             Thread.sleep(50);
  18.         }
  19.      }catch (InterruptedException e) {
  20.          System.out.println("InterruptThread1.run() interrupted!");
  21.     }
  22.     }

  23.     public static void main(String[] args) throws Exception {
  24.         // 将任务交给一个线程执行
  25.         InterruptThread1 t = new InterruptThread1();
  26.         t.start();

  27.         // 运行一断时间中断线程
  28.         Thread.sleep(100);
  29.         System.out.println("****************************");
  30.         System.out.println("Interrupted Thread!");
  31.         System.out.println("****************************");
  32.         t.interrupt();
  33.     }
  34. }
运行结果
  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.     public void run() {
  10.         // 检查程序是否发生中断
  11.         while (!Thread.interrupted()) {
  12.             System.out.println("I am running!");

  13.             for (int i = 0; i < 900000; i++) {
  14.                 d = d + (Math.PI + Math.E) / d;
  15.             }
  16.         }
  17.     }

  18.     public static void main(String[] args) throws Exception {
  19.         // 将任务交给一个线程执行
  20.         InterruptThread1 t = new InterruptThread1();
  21.         t.start();

  22.         // 运行一断时间中断线程
  23.         Thread.sleep(100);
  24.         System.out.println("****************************");
  25.         System.out.println("Interrupted Thread!");
  26.         System.out.println("****************************");
  27.         t.interrupt();
  28.     }
  29. }
运行结果
  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.     public void run() {
  10.         try {
  11.             // 检查程序是否发生中断
  12.             while (!Thread.interrupted()) {
  13.                 System.out.println("I am running!");
  14.                 // before sleep
  15.                 Thread.sleep(20);
  16.                 //after sleep
  17.                 System.out.println("Calculating");
  18.                 for (int i = 0; i < 900000; i++) {
  19.                     d = d + (Math.PI + Math.E) / d;
  20.                 }
  21.             }

  22.         } catch (InterruptedException e) {
  23.             System.out.println("InterruptThread1.run() Exception!");
  24.         }

  25.         System.out.println("InterruptThread1.run() end!");
  26.     }

  27.     public static void main(String[] args) throws Exception {
  28.         // 将任务交给一个线程执行
  29.         InterruptThread1 t = new InterruptThread1();
  30.         t.start();

  31.         // 运行一断时间中断线程
  32.         Thread.sleep(200);
  33.         System.out.println("****************************");
  34.         System.out.println("Interrupted Thread!");
  35.         System.out.println("****************************");
  36.         t.interrupt();
  37.     }
  38. }
运行结果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.             for (int i = 0; i < 900000; i++) {
  15.                 d = d + (Math.PI + Math.E) / d;
  16.             }
  17.         }
  18.         //做一些清理工作
  19.         System.out.println( "Thread is exiting under request..." );
  20.     }

  21.     public static void main(String[] args) throws Exception {
  22.         // 将任务交给一个线程执行
  23.         InterruptThread1 t = new InterruptThread1();
  24.         t.start();

  25.         // 运行一断时间中断线程
  26.         Thread.sleep(100);
  27.         System.out.println( "Asking thread to stop..." );
  28.         t.stop = true;

  29.         Thread.sleep(1000 );
  30.         System.out.println( "Stopping application..." );
  31.     }
  32. }
例6:通过SocketException异常中断阻塞线程
  1. import java.io.IOException;
  2. import java.net.ServerSocket;
  3. import java.net.Socket;

  4. /**
  5.  * 通过SocketException异常中断阻塞线程.
  6.  * @version V1.0 ,2011-4-17
  7.  * @author xiahui
  8.  */
  9. public class InterruptThread2 extends Thread {
  10.     volatile boolean stop = false;
  11.     volatile ServerSocket socket;

  12.     public void run() {
  13.         try {
  14.             socket = new ServerSocket(7856);
  15.         } catch (IOException e) {
  16.             System.out.println("Could not create the socket...");
  17.             return;
  18.         }
  19.         while (!stop) {
  20.             System.out.println("Waiting for connection...");
  21.             try {
  22.                 Socket sock = socket.accept();
  23.             } catch (IOException e) {
  24.                 System.out.println("accept() failed or interrupted...");
  25.             }
  26.         }
  27.         System.out.println("Thread exiting under request...");
  28.     }

  29.     public static void main(String args[]) throws Exception {
  30.         InterruptThread2 thread = new InterruptThread2();
  31.         System.out.println("Starting thread...");
  32.         thread.start();
  33.         Thread.sleep(3000);
  34.         System.out.println("Asking thread to stop...");
  35.         
  36.         /*由于线程处理阻塞状态,interrupt不产生任何作用*/
  37.         //System.out.println( "Interrupting thread..." );
  38.         //thread.interrupt();
  39.         
  40.         thread.stop = true;
  41.         thread.socket.close();
  42.         Thread.sleep(3000);
  43.         System.out.println("Stopping application...");

  44.     }
  45. }
运行结果
  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...


参考文献
1.用interrupt()中断Java线程. http://hapinwater.iteye.com/blog/310558
2.Java Thread.interrupt 害人! 中断JAVA线程. http://www.blogjava.net/jinfeng_wang/archive/2008/04/27/196477.html
阅读(6981) | 评论(0) | 转发(1) |
给主人留下些什么吧!~~