2013-11-15 69 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)听众失败不会覆盖任务成功。)

相关问题