首页 > 代码库 > 漫谈并发编程(四):终结任务

漫谈并发编程(四):终结任务

使用状态变量来终结任务

     有时我们可以使用一个状态变量(如布尔值)来终结任务的执行,这种方式非常平和,且提供给你机会在任务终止前做一些操作。如:
public class StateStopTask implements Runnable{
     private static volatile boolean isCancled = false;
     public void run() {
          while(true) {
               if(isCancled == true) {
                    System.out.println("StateStopTask is stop");
                    return;
               }
          }
     }

     public static void main(String []args) {
          new Thread(new StateStopThread()).start();
          Thread.sleep(3000);
          isCancled = true;
     }
}
     或者直接使用Thread.interrupt()来设置线程的中断标识,并且在程序中检测该标识,可以避免状态变量的定义。
public class StateStopTask implements Runnable{
     public void run() {
          while(!Thread.currentThread().isInterrupted()) {
                System.out.println("StateStopTask is running");
          }
          System.out.println("StateStopTask is stopping");
     }
     public static void main(String []args) {
          Thread t = new Thread(new StateStopThread()).start();
          Thread.sleep(3000);
          t.interrupt();
     }
}

在阻塞时终结

     前面使用状态变量只能在线程运行到该检测时才能终止,有时我们需要线程无论在何时何地都能够被终止,尤其是在阻塞的时候。一个任务进入阻塞状态,可能有如下原因:
  1. 通过调用sleep(milliseconds)使任务进入休眠状态,在这种情况下,任务在指定的时间内不会运行。
  2. 你可以通过wait()使线程挂起。直到线程得到了notify()或notifyAll()消息(或者在JavaSE5的java.util.concurrent类库中等价的signal()或signalAll()消息),线程才会进入就绪状态。
  3. 任务在等待某个输入输出完成。
  4. 任务试图在某个对象上调用其同步控制方法,但是对象锁不可用,因为另一个任务已经获取了这个锁。
中断
     程序在由于sleep或者wait()导致的阻塞情况下,如果被调用interrupt()方法将抛出interruptedExcetion异常,并且中断状态将清除。程序在由于IO和锁的阻塞时,调用interrupt()方法不会抛出interruptedException,但会设置中断状态。使用interrupted()可以检测中断状态并且如果正处于中断则清除中断状态,所以在程序中一般使用下面的方式检测中断,并做善后处理:
public class InterruptedTask implements Runnable{
     public void run() {
          while(!Thread.currentThread().interrupted()) {
               try {
                    System.out.println("InterruptedTask running");
                    Thread.sleep(100);     
               } catch (InterruptedException e) {
                    System.out.println("interrupted by InterruptedException ")
               }     
          }
          System.out.println("InterruptedTask Interrupted")

     }
}
     现代java代码不推荐直接操作Thread对象,转而尽量通过Executor来执行所有操作。如果你在Executor上调用shutdownNow(),那么它将发送一个interrupt()调用给它启动的所有线程。这样做是常见的,因为一个Executor通常执行同一类任务,所以经常会希望关闭Executor的所有任务。然后,你有时会希望只中断单一的任务。如果使用Executor,那么通过调用submit()而不是executor()来启动任务,就可以持有该任务的上下文,submit()将返回一个泛型Future<?>,其中有一个未修饰的参数,因为你不能调用get(),使用这个Futrue对象可以调用cancle(),如果传递true给cancle(),那么在这个线程上就会调用interrupt()方法。
     一般由于锁而导致的阻塞无法中断,但原子锁(ReentrantLock)支持可中断的阻塞操作lockInterruptibly()。


漫谈并发编程(四):终结任务