5

I have a Worker class that implements Runnable and has a run() method which may raise exceptions in the event of a conflict, and return early. When it does, that thread needs to be put back into the queue to be run again.

From looking at this question, it seems I need to rewrite with Callable. Is that correct? There's no way to do this with Runnable?

Community
  • 1
  • 1
temporary_user_name
  • 35,956
  • 47
  • 141
  • 220
  • Just use http://docs.oracle.com/javase/7/docs/api/java/util/concurrent/Executors.html#newCachedThreadPool%28%29 – Matt Ball Dec 10 '12 at 22:36
  • I've already read that. It lists methods and types and all but doesn't give any examples or say anything about exception handling with Runnables. I edited the question to be clearer. – temporary_user_name Dec 10 '12 at 22:40
  • 2
    You could also have a look at [this](http://docs.oracle.com/javase/tutorial/essential/concurrency/executors.html) – MadProgrammer Dec 10 '12 at 22:43
  • Are you concerned that a `Runnable` which throws an uncaught runtime exception won't be returned to the pool? – Matt Ball Dec 10 '12 at 23:19
  • Part of my `run()` method involves this: `try{//thingThatThrowsException}catch (TransactionAbortException e){return;}` I'm afraid that yes, if it returns here, the Runnable will not do its job. – temporary_user_name Dec 10 '12 at 23:21
  • If you're handling the exception in the `Runnable`, why not return it to the pool there? – millimoose Dec 10 '12 at 23:50

2 Answers2

4

Well you can have the worker thread do it itself. If you have control of the executor.

class RequeableWorker implement Runnable{
  private final ExecutorService e;
  public RequeableWorker(ExecutorService e){this.e =e;}

  public void run(){
     try{
        //do work
     }catch(RuntimeException ex){
        e.submit(this);
        throw ex;
     }
  }
}

Or as your answer suggests having the waiting thread of a Future re-queue.

public void workOrRequeue(){
    for(;;){
       Future<?> future = e.submit(someCallable());
       try{
          future.get();
          return;
       }catch(ExecutionException ex){
          //maybe log, ex.printStackTrace();
       }
    }
}
John Vint
  • 39,695
  • 7
  • 78
  • 108
  • ...You can do that? that will work? If I declare an ExecutorService in the main thread, I can pass it in as an argument to the worker, and have the worker resubmit itself to the queue? – temporary_user_name Dec 10 '12 at 23:03
  • What if the worker takes other arguments? When it resubmits itself to the queue, will they be included in the new submission as well? – temporary_user_name Dec 10 '12 at 23:05
  • @Aerovistae Generally speaking, the ExecutorService is composed of a work queue and threads. If you pass the ExecutorService and submit to it you are simply placing the runnable on the ES work queue. It is simply delegating, you can see it is done here too http://docs.oracle.com/javase/1.5.0/docs/api/java/util/concurrent/ExecutorCompletionService.html – John Vint Dec 11 '12 at 15:48
  • That poses a different sort of problem. If the worker needs to be re defined you are posed with the concern of having the ES do too much work retrieving the new data. If the ES cannot actually get this new data you need to use the second example I listed. Lastly, if the RequeableWorker can in fact attain the new parameters then you can just get them before `submit`ing – John Vint Dec 11 '12 at 15:49
2

As say the docs for Future.get():

Throws:

[...]

ExecutionException - if the computation threw an exception

millimoose
  • 39,073
  • 9
  • 82
  • 134