java.util.concurrent.RejectedExecutionException – How to solve RejectedExecutionException
In this example we are going to talk about java.util.concurrent.RejectedExecutionException
. When using an Executor
to run your threads, it might reach a state where it cannot run the task you asked him to. This can happen for a number of reason, as we will demonstrate in this example. It is worth noting that this is a java.lang.RuntimeException
1. A simple Executor Example
To demonstrate this exception we are going to create a simple Java application that uses a ThreadPoolExecutor
to execute a number of worker threads. Let’s see how you can do that.
Here a simple worker thread:
Worker.java:
package com.javacodegeeks.core.rejectedexecutionexception; public class Worker implements Runnable { private int ID; public Worker(int id){ this.ID = id; } @Override public void run() { try{ Thread curThread = Thread.currentThread(); System.out.println(curThread.getName() + " currently executing the task " + ID); Thread.sleep(500); System.out.println(curThread.getName() + " just completed the task " + ID); } catch(Exception e){ System.out.println(e); } } public int getID() { return ID; } public void setID(int iD) { ID = iD; } }
An here is how you can use an ThreadPoolExecutor
to create a number of threads to execute your tasks
RejectedExecutionExceptionExample.java:
package com.javacodegeeks.core.rejectedexecutionexception; import java.util.concurrent.ArrayBlockingQueue; import java.util.concurrent.ExecutorService; import java.util.concurrent.ThreadPoolExecutor; import java.util.concurrent.TimeUnit; public class RejectedExecutionExceptionExample { public static void main(String[] args) { ExecutorService executor = new ThreadPoolExecutor(3, 3, 0L, TimeUnit.MILLISECONDS, new ArrayBlockingQueue<Runnable>(15)); Worker tasks[] = new Worker[10]; for(int i=0; i<10; i++){ tasks[i] = new Worker(i); executor.execute(tasks[i]); } executor.shutdown(); } }
If you run the program, this is the output:
pool-1-thread-2 currently executing the task 1 pool-1-thread-3 currently executing the task 2 pool-1-thread-1 currently executing the task 0 pool-1-thread-1 just completed the task 0 pool-1-thread-2 just completed the task 1 pool-1-thread-1 currently executing the task 3 pool-1-thread-3 just completed the task 2 pool-1-thread-2 currently executing the task 4 pool-1-thread-3 currently executing the task 5 pool-1-thread-3 just completed the task 5 pool-1-thread-1 just completed the task 3 pool-1-thread-2 just completed the task 4 pool-1-thread-1 currently executing the task 7 pool-1-thread-3 currently executing the task 6 pool-1-thread-2 currently executing the task 8 pool-1-thread-2 just completed the task 8 pool-1-thread-3 just completed the task 6 pool-1-thread-1 just completed the task 7 pool-1-thread-2 currently executing the task 9 pool-1-thread-2 just completed the task 9
Everything went normal at this point. We create a ThreadPoolExecutor
with pool size of 3. This means that it will create 3 threads that will be charged with the execution of our tasks-workers. As we submit new tasks to the ThreadPoolExecutor
, he will place them in a BlockingQueue, as some of its 3 threads might be currently occupied with other tasks and thus the new tasks will have to wait until one of these 3 threads becomes available. In this particular case we use an ArrayBlockingQueue
of size 15, to do this job (for reason that should become clear later on). After that, we create 10 tasks and we submit them to out ThreadPoolExecutor
.
2. A simple case of RejectedExecutionException
One of the causes of RejectedExecutionException
is when we try to execute a new task after we’ve shutdown the executor. When shutdown()
is called upon an executor, older tasks might still progress, but it allows no more tasks to be submitted.
Let’s see what happens in the case where we violate this rule :
RejectedExecutionExceptionExample.java:
package com.javacodegeeks.core.rejectedexecutionexception; import java.util.concurrent.ArrayBlockingQueue; import java.util.concurrent.ExecutorService; import java.util.concurrent.ThreadPoolExecutor; import java.util.concurrent.TimeUnit; public class RejectedExecutionExceptionExample { public static void main(String[] args) { ExecutorService executor = new ThreadPoolExecutor(3, 3, 0L, TimeUnit.MILLISECONDS, new ArrayBlockingQueue<Runnable>(15)); Worker tasks[] = new Worker[10]; for(int i=0; i<10; i++){ tasks[i] = new Worker(i); executor.execute(tasks[i]); } executor.shutdown(); executor.execute(tasks[0]); } }
If you run the program, this is the output:
pool-1-thread-2 currently executing the task 1 Exception in thread "main" pool-1-thread-3 currently executing the task 2 pool-1-thread-1 currently executing the task 0 java.util.concurrent.RejectedExecutionException: Task com.javacodegeeks.core.rejectedexecutionexception.Worker@1e344422 rejected from java.util.concurrent.ThreadPoolExecutor@796523ab[Shutting down, pool size = 3, active threads = 3, queued tasks = 7, completed tasks = 0] at java.util.concurrent.ThreadPoolExecutor$AbortPolicy.rejectedExecution(Unknown Source) at java.util.concurrent.ThreadPoolExecutor.reject(Unknown Source) at java.util.concurrent.ThreadPoolExecutor.execute(Unknown Source) at com.javacodegeeks.core.rejectedexecutionexception.RejectedExecutionExceptionExample.main(RejectedExecutionExceptionExample.java:21) pool-1-thread-2 just completed the task 1 pool-1-thread-1 just completed the task 0 pool-1-thread-2 currently executing the task 3 pool-1-thread-3 just completed the task 2 pool-1-thread-1 currently executing the task 4 pool-1-thread-3 currently executing the task 5 pool-1-thread-3 just completed the task 5 pool-1-thread-2 just completed the task 3 pool-1-thread-1 just completed the task 4 pool-1-thread-2 currently executing the task 7 pool-1-thread-3 currently executing the task 6 pool-1-thread-1 currently executing the task 8 pool-1-thread-3 just completed the task 6 pool-1-thread-2 just completed the task 7 pool-1-thread-1 just completed the task 8 pool-1-thread-3 currently executing the task 9 pool-1-thread-3 just completed the task 9
So when shutdown()
is called, no more tasks are allowed to be executed. If that is not so, RejectedExecutionException
is raised.
3. A second case of RejectedExecutionException
Another case of RejectedExecutionException
, appears when an Executor cannot take any more tasks under its responsibility. This happens when the limit of its local “memory” is reached. In our case that “local” memory is an ArrayBlockingQueue
of size 15. If we try to submit more tasks than the ArrayBlockingQueue
can hold, then RejectedExecutionException
arises.
Let’s see an example :
RejectedExecutionExceptionExample.java:
package com.javacodegeeks.core.rejectedexecutionexception; import java.util.concurrent.ArrayBlockingQueue; import java.util.concurrent.ExecutorService; import java.util.concurrent.ThreadPoolExecutor; import java.util.concurrent.TimeUnit; public class RejectedExecutionExceptionExample { public static void main(String[] args) { ExecutorService executor = new ThreadPoolExecutor(3, 3, 0L, TimeUnit.MILLISECONDS, new ArrayBlockingQueue<Runnable>(15)); Worker tasks[] = new Worker[20]; for(int i=0; i<20; i++){ tasks[i] = new Worker(i); executor.execute(tasks[i]); } executor.shutdown(); executor.execute(tasks[0]); } }
Now as you can, see our ArrayBlockingQueue
can hold no more than 15 threads. But we submit to it 20 threads. And because we’ve introduced a bit of delay in the threads (with Thread.sleep()
), our 3 workers are occupied for sometime. So, our ThreadPoolExecutor
has to put newly submitted tasks to the ArrayBlockingQueue
, because they cannot be executed instantly. Consequently, when the submitted tasks are more than he can handle (more than 15), then RejectedExecutionException
is thrown.
4. How to solve RejectedExecutionException
The first things you want to check are the two cases :
- Be careful not to submit new tasks after having called
shutdown()
on theExecutor
. - Do not give the
Executor
more tasks than he can handle.
Not surprisingly, the second case can be easily resolved. You could just use a data structure that does not impose a size limit. For example a LinkedBlockingQueue
. So if you still face this problem after using LinkedBlockingQueue
, you should focus on the first case. If the first case is not the cause of your problem, then you should probably look for more complex problem. For example, your memory is filling up because some of your threads have deadlocked and the LinkedBlockingQueue
keeps filling up, and don’t forget is still the limit of the available memory that the JVM has.
I want to focus a bit more o that second case, as it might be hidden often. Do not forget that it is possible to submit more that 15 tasks in the ThreadPoolExecutor
even in the case where he uses the ArrayBlockingQueue
, as long as you give it some time to complete some of the tasks before submitting new ones, so that the 3 workers smoothly consume the ArrayBlockingQueue
and does not get clogged up.
Let’s see this example :
RejectedExecutionExceptionExample.java:
package com.javacodegeeks.core.rejectedexecutionexception; import java.util.concurrent.ArrayBlockingQueue; import java.util.concurrent.ExecutorService; import java.util.concurrent.ThreadPoolExecutor; import java.util.concurrent.TimeUnit; public class RejectedExecutionExceptionExample { public static void main(String[] args) throws InterruptedException { ExecutorService executor = new ThreadPoolExecutor(3, 3, 0L, TimeUnit.MILLISECONDS, new ArrayBlockingQueue<Runnable>(15)); Worker tasks[] = new Worker[20]; for(int i=0; i<10; i++){ tasks[i] = new Worker(i); executor.execute(tasks[i]); } Thread.sleep(3000); for(int i=10; i<20; i++){ tasks[i] = new Worker(i); executor.execute(tasks[i]); } executor.shutdown(); } }
From the output, you can see that the program is executed normally.
pool-1-thread-1 currently executing the task 0 pool-1-thread-3 currently executing the task 2 pool-1-thread-2 currently executing the task 1 pool-1-thread-1 just completed the task 0 pool-1-thread-3 just completed the task 2 pool-1-thread-1 currently executing the task 3 pool-1-thread-2 just completed the task 1 pool-1-thread-2 currently executing the task 5 pool-1-thread-3 currently executing the task 4 pool-1-thread-2 just completed the task 5 pool-1-thread-1 just completed the task 3 pool-1-thread-3 just completed the task 4 pool-1-thread-1 currently executing the task 7 pool-1-thread-2 currently executing the task 6 pool-1-thread-3 currently executing the task 8 pool-1-thread-1 just completed the task 7 pool-1-thread-3 just completed the task 8 pool-1-thread-2 just completed the task 6 pool-1-thread-1 currently executing the task 9 pool-1-thread-1 just completed the task 9 pool-1-thread-3 currently executing the task 10 pool-1-thread-1 currently executing the task 12 pool-1-thread-2 currently executing the task 11 pool-1-thread-3 just completed the task 10 pool-1-thread-1 just completed the task 12 pool-1-thread-1 currently executing the task 14 pool-1-thread-2 just completed the task 11 pool-1-thread-3 currently executing the task 13 pool-1-thread-2 currently executing the task 15 pool-1-thread-3 just completed the task 13 pool-1-thread-2 just completed the task 15 pool-1-thread-2 currently executing the task 17 pool-1-thread-1 just completed the task 14 pool-1-thread-3 currently executing the task 16 pool-1-thread-1 currently executing the task 18 pool-1-thread-1 just completed the task 18 pool-1-thread-3 just completed the task 16 pool-1-thread-2 just completed the task 17 pool-1-thread-1 currently executing the task 19 pool-1-thread-1 just completed the task 19
You should be careful, because you might thing that your ThreadPoolExecutor
can successfully take more than 15 tasks, but that is only because the are being progressively consumed by the 2 workers.
Download the Source Code
This was an example of java.util.concurrent.RejectedExecutionException
and How to solve RejectedExecutionException
.
You can download the full source code of this example here : RejectedExecutionExceptionExample.zip
Well that was 5 minutes of my life i can’t get back. How can you possibly think this is a reasonable solution to overloading tasks onto an executor ? Just put a sleep between batches of calls ???
output of the program
Given:
1. public class Threads2 implements Runnable {
2.
3. public void run() {
4. System.out.println(“run.”);
5. throw new RuntimeException(“Problem”);
6. }
7. public static void main(String[] args) {
8. Thread t = new Thread(new Threads2());
9. t.start();
10. System.out.println(“End of method.”);
11. }
12. }