2013-11-15 67 views
3

我:運行偵聽器時任務返回

  1. ExecutorService別人提供。
  2. A Runnable任務在中斷後自行清理。
  3. 一個Runnable聽衆

我的工作是在其上運行ExecutorService的任務,然後在同一ExecutorService任務返回後的某個時間運行監聽器,無論是正常(通過return)或拋出一個異常。我回到我的客戶Future,他(有時)撥打cancel(true)

我的第一個想法是使用Guava的ListenableFuture.addListener ...但是這會在取消未來之後立即執行偵聽器,而不是在任務返回之後執行。但是,如果在將偵聽器添加到將來之前完成任務,那麼它具有很好的屬性,即偵聽器將立即執行。我已將此解決方案包含在下面的SSCCE中。

從下面的例子中,我如下:

Task Started 
Task Canceling 
Task Cancelled 
**Listener Started** 

其實得到的是:

Running 
Canceling 
**Listener** 
Cancelled 

在這個例子中,我允許任何改變在myMethod裏面,剩下的就是提供給我的。

public static void main(String[] args) { 

    Runnable task = new Runnable() { 
     public void run() { 
      try { 
       System.out.println("Task Started"); 
       interruptableWork(); 
       System.out.println("Task Completed"); 
      } catch (InterruptedException e) { 
       System.out.println("Task Canceling"); 
       cleanup(); 
       System.out.println("Task Cancelled"); 
       Thread.currentThread().interrupt(); 
      } 
     } 

     private void interruptableWork() throws InterruptedException { 
      TimeUnit.SECONDS.sleep(2); 
     } 

     private void cleanup() { 
      try { 
       TimeUnit.SECONDS.sleep(2); 
      } catch (InterruptedException ignored) { 
      } 
     } 
    }; 

    Runnable listener = new Runnable() { 
     public void run() { 
      System.out.println("**Listener Started**"); 
     } 
    }; 

    ExecutorService executor = Executors.newCachedThreadPool(); 

    Future<?> future = myMethod(task, listener, executor); 

    try { 
     TimeUnit.SECONDS.sleep(1); 
    } catch (InterruptedException ignored) { 
    } 

    future.cancel(true); 

} 

private static Future<?> myMethod(Runnable task, Runnable listener, ExecutorService executor) { 
    ListeningExecutorService listeningExecutor = MoreExecutors.listeningDecorator(executor); 
    ListenableFuture<?> future = listeningExecutor.submit(task); 
    future.addListener(listener, executor); 
    return future; 
} 

回答

3

我想嘗試的第一件事就是來包裝任務,並監聽了一個Runnable

Runnable wrappedTask = new Runnable() { 
    public void run() { 
    try { 
     task.run(); 
    } finally { 
     try { 
     listener.run(); 
     } catch (RuntimeException e) 
     // log failure? 
     } 
    } 
    } 
}; 
executor.submit(wrappedTask); 

(當然,不是日誌監聽失敗,你可以讓失敗的傳播。我選擇記錄(a),以便聽衆失敗不會覆蓋任務失敗,(b)聽衆失敗不會覆蓋任務成功。)

相關問題