2013-11-15 2 views
3

у меня есть:Run слушателем, когда задача возвращает

  1. ExecutorService что кто-то предоставил.
  2. A Runnable Задача, которая очищается после себя, когда она прерывается.
  3. Runnable слушатель

Моя работа состоит в том, чтобы выполнить задачу на ExecutorService и затем запустить слушателя на том же ExecutorService через некоторое время после того как задача вернулась, либо нормально (через return) или бросать исключение. Я возвращаюсь к своему клиенту Future, и он (иногда) звонит cancel(true).

Моя первая мысль заключалась в использовании Guava's 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); 

(Конечно, вместо неудач регистрации слушателя, вы могли бы позволить отказ распространяющихся. Я выбрал log (a), чтобы сбой слушателя не отменял отказ задачи и (b), так что отказ слушателя не отменяет успех задачи.)

Смежные вопросы