2017-07-03 60 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。 –