java线程技术7_线程中断

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.             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...
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值