任务返回时运行监听器

时间:2013-11-15 15:20:48

标签: java multithreading listener guava future

我有:

  1. 其他人提供的ExecutorService
  2. Runnable任务在中断后自行清理。
  3. Runnable听众
  4. 我的工作是在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;
    }
    

1 个答案:

答案 0 :(得分: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)以便侦听器失败。 t覆盖任务成功。)