2017-07-03 58 views
5

我想取消提交给ExecutorService的任务,从而允许相应的线程从队列中选择新的任务。取消java中的未来任务

现在这个问题已经在这个论坛上多次回答过......比如检查Thread.currentThread().interrupt()catch (InterruptedException e)。但是如果控制流横跨多种方法,那么放这些检查会使代码笨拙。所以如果可能的话,请在java中提出一些优雅的方法来实现这个功能。

我面临的问题是future.cancel实际上不会取消任务。相反,它仅向正在执行的任务发送InterruptedException,这是标记自己完成并释放线程的任务的责任。

所以我所做的就是只要在执行过程中的任何地方抛出异常,我就不得不放置下面的代码块,这显然看起来不太好!

if(e instanceof InterruptedException) { 
        throw e; 
       } 

那么,如何实现在下面的代码片段此功能:

public class MonitoringInParallelExp { 

     public static void main(String[] args) throws InterruptedException { 
      MyClass1 myClass1 = new MyClass1(); 
      ExecutorService service = Executors.newFixedThreadPool(1); 
      Future<String> future1 = service.submit(myClass1); 
      Thread.sleep(2000); 
      System.out.println("calling cancel in Main"); 
      future1.cancel(true); 
      System.out.println("finally called cancel in Main"); 
      service.shutdown(); 
     } 
    } 

    class MyClass1 implements Callable<String> { 
     @Override 
     public String call() throws Exception { 
      try{ 
       MyClass2 myClass2 = new MyClass2(); 
       myClass2.method2(); 
      } catch (Exception e){ 
       if(e instanceof InterruptedException) { 
        System.out.println("call:"+"e instanceof InterruptedException="+"true"); 
        throw e; 
       } 
       System.out.println("Got exception in method1. " + e); 
      } 
      System.out.println("returning Myclass1.method1.exit"); 
      return "Myclass1.method1.exit"; 
     } 
    } 

    class MyClass2 { 
     public void method2() throws Exception{ 
      try{ 
       MyClass3 myClass3 = new MyClass3(); 
       myClass3.method3(); 
      } catch (Exception e){ 
       if(e instanceof InterruptedException) { 
        System.out.println("method2:"+"e instanceof InterruptedException="+"true"); 
        throw e; 
       } 
       System.out.println("Got exception in method2. " + e); 

       // in case the exception isn't InterruptedExceptionm, do some work here 
      } 
     } 
    } 

    class MyClass3 { 
     public void method3() throws Exception{ 
      try{ 
       Thread.sleep(10000); 
      } catch (Exception e){ 
       if(e instanceof InterruptedException) { 
        System.out.println("method3:"+"e instanceof InterruptedException="+"true"); 
        throw e; 
       } 
       System.out.println("Got exception in method3. " + e); 
       throw new MyException(); 
      } 
     } 
    } 

    class MyException extends Exception { 

    } 

回答

4

如果中断Callable与否,因为在这一点上它已经太迟了不要紧

try{ 
    MyClass2 myClass2 = new MyClass2(); 
    myClass2.method2(); 
} catch (Exception e){ 

您拨打future1.cancel(true);Thread.sleep(2000)实际上不是取消正在进行任务(在这种情况下,您的method2调用)它只意味着它应该在它开始之前被取消。

该文档指出这一点 https://docs.oracle.com/javase/7/docs/api/java/util/concurrent/Future.html#cancel(boolean)

试图取消对此任务的执行。如果任务已完成,已被取消或因其他原因无法取消,此尝试将失败。如果成功,并且此任务在调用取消时尚未开始,则此任务不应运行。如果任务已经启动,则mayInterruptIfRunning参数确定执行此任务的线程是否应该中断以试图停止任务。

如果你想取消正在进行的任务,你想使用volatile boolean标志或类似的东西。

+0

future1.cancel(true)肯定会发送InterruptedException,因为主线程只睡2000ms,而method3需要10000ms才能完成。 现在method3将检查异常是否是instanceof InterruptedException或不是。如果是,那么它会将它传递给调用者(方法2)。 我不想在整个工作流程的任何地方保持这种检查,最终将其传递给MyClass1.call()方法。 在这个世界上有没有其他优雅的方式来实现这个功能? – gautam

+0

@gautam - 使用回调机制。将对象传递给其他类并在InterruptedException期间捕获一个方法。对于回调机制,请参阅https://stackoverflow.com/questions/36449040/executing-java-callback-on-a-new-thread/36451028#36451028。 –