Rivu Chakraborty
Rivu Chakraborty

Reputation: 1372

Use custom RejectedExecutionHandler

While using java.util.concurrent.ThreadPoolExecutor I wanted to try to execute a rejected task once more. Is it really possible? I have heard of RejectedExecutionHandler interface. There are many available(known) instances of the interface(RejectedExecutionHandler) such as ThreadPoolExecutor.AbortPolicy, ThreadPoolExecutor.CallerRunsPolicy, ThreadPoolExecutor.DiscardOldestPolicy, ThreadPoolExecutor.DiscardPolicy etc. but the problem is that they do not allow to retry the execution.

Upvotes: 3

Views: 9339

Answers (3)

ruslangm
ruslangm

Reputation: 703

I'll add few points to the comment by @Viscent Huang.
First, this solution makes sense only if your ThreadPoolExecutor is using BlockingQueue.
Second, this solution also provides risk that you may have a deadlock in case your threadpool is full because you're inserting runnable in a blocking manner in a threadpool which might be already filled.
For example this code may easily cause such problem:

CompletableFuture.supplyAsync(
        () -> {
            // some computation intensive task
        }, executors
).thenAcceptAsync(
        res -> {
            // handling the result
        }, executors);

What I suggest is to handle rejected threads in a separate threadpool to avoid deadlock. So finally your code may look like this:

public class CustomRejectedExecutionHandler implements RejectedExecutionHandler {
    private final Executor rejectedExecutionThread = Executors.newFixedThreadPool(1);

    @Override
    public void rejectedExecution(Runnable r, ThreadPoolExecutor executor) {
        rejectedExecutionThread.execute(() -> {
            try {
                executor.getQueue().put(r);
            } catch (Exception e) {
                // handle exception
            }
        });
    }
}

Upvotes: 0

Viscent Huang
Viscent Huang

Reputation: 71

Below is a retry-enabled RejectedExecutionHandler that does not require an additional ThreadPoolExecutor. It's is more practical: when a task was rejected, the rejected task will be put into the workerQueue of ThreadPoolExecutor in blocking mode, which makes the task submitter wait some time before the ThreadPoolExecutor can process any more tasks.

new RejectedExecutionHandler() {

        @Override
        public void rejectedExecution(Runnable r, ThreadPoolExecutor executor) {
            if (!executor.isShutdown()) {
                try {
                    executor.getQueue().put(r);
                } catch (InterruptedException e) {
                    ;
                }
            }

        }

    }

Upvotes: 7

Rivu Chakraborty
Rivu Chakraborty

Reputation: 1372

Yes it is possible to retry the execution of the rejected task. The best way to retry the execution is to use an alternate executor. You may declare a custom RejectedExecutionHandler class simply like as you do this with other interfaces. Here are some code samples:

public class MyRejectedExecutionHandler implements RejectedExecutionHandler {



@Override
public void rejectedExecution(Runnable worker, ThreadPoolExecutor executor) {
    // TODO Auto-generated method stub
    System.out.println(worker.toString()+" is Rejected");

    System.out.println("Retrying to Execute");
    try{
        //Re-executing with alternateExecutor
        MainClass.alternateExecutor.execute(worker);
        System.out.println(worker.toString()+" Execution Started");
    }
    catch(Exception e)
    {
        System.out.println("Failure to Re-exicute "+e.getMessage());
    }
}

}

You can find more details about this at: http://examples.javacodegeeks.com/core-java/util/concurrent/rejectedexecutionhandler/java-util-concurrent-rejectedexecutionhandler-example/

Upvotes: 2

Related Questions