19

My Android app has to deal with arriving messages which frequently come in bunches (especially during periods of flaky connectivity). I handle these incoming messages in AsyncTasks so that I don't interfere with the UI thread. If too many messages come in at once, I get a RejectedExecutionException. My error stack looks like this:

10-22 14:44:49.398: E/AndroidRuntime(17834): Caused by: java.util.concurrent.RejectedExecutionException: Task android.os.AsyncTask$3@414cbe68 rejected from java.util.concurrent.ThreadPoolExecutor@412716b8[Running, pool size = 128, active threads = 22, queued tasks = 0, completed tasks = 1323]
10-22 14:44:49.398: E/AndroidRuntime(17834):    at java.util.concurrent.ThreadPoolExecutor$AbortPolicy.rejectedExecution(ThreadPoolExecutor.java:1967)
10-22 14:44:49.398: E/AndroidRuntime(17834):    at java.util.concurrent.ThreadPoolExecutor.reject(ThreadPoolExecutor.java:782)
10-22 14:44:49.398: E/AndroidRuntime(17834):    at java.util.concurrent.ThreadPoolExecutor.execute(ThreadPoolExecutor.java:1303)
10-22 14:44:49.398: E/AndroidRuntime(17834):    at android.os.AsyncTask.executeOnExecutor(AsyncTask.java:564)

I'm running the tasks with task.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR) so that incoming messages are processed in parallel.

What is confusing about this, and different from related StackOverflow questions that I can find (e.g. here and here), is that the number of active threads and queued tasks don't seem to be bumping up against the limits (which seem to be 128 and 10, respectively). See the stacktrace:

ThreadPoolExecutor@412716b8[Running, pool size = 128, active threads = 22, queued tasks = 0, completed tasks = 1323]

Why would I be getting this error message?

Community
  • 1
  • 1
abeboparebop
  • 7,396
  • 6
  • 37
  • 46
  • You found any solution? – Muhammad Babar Dec 15 '15 at 13:08
  • I believe that the accepted answer is correct, but I never did understand why the number of active threads in the error message was below the limit (i.e. 22 instead of 128). Perhaps some previously-active threads had ended by the time the error was thrown. – abeboparebop Dec 15 '15 at 13:39

2 Answers2

29

Why would I be getting this error message?

If the ThreadPoolExecutor is still running, you would get this error message only if you have exceeded the number of tasks that can be queued by the ThreadPoolExecutor. The only time the RejectedExecutionException is thrown is by the ThreadPoolExecutor.AbortPolicy which is the default RejectedExecutionHandler.

To quote from the javadocs:

If a request cannot be queued, a new thread is created unless this would exceed maximumPoolSize, in which case, the task will be rejected.

There is a maximum number of tasks. See this question/answer here: Is there a limit of AsyncTasks to be executed at the same time?

Here's a link for the sourcecode for AsyncTask.

private static final int CORE_POOL_SIZE = 5;
private static final int MAXIMUM_POOL_SIZE = 128;

private static final BlockingQueue<Runnable> sWorkQueue =
        new LinkedBlockingQueue<Runnable>(10);

private static final ThreadPoolExecutor sExecutor =
    new ThreadPoolExecutor(CORE_POOL_SIZE, MAXIMUM_POOL_SIZE,
        KEEP_ALIVE, TimeUnit.SECONDS, sWorkQueue, sThreadFactory);

So it looks like it starts at 5 threads, has a queue of 10. Once the queue is full it can start up to 128 threads. So it looks like you have exceeded 138 simultaneous requests.

ThreadPoolExecutor@412716b8[Running, pool size = 128, active threads = 22, queued tasks = 0, completed tasks = 1323]

Trying to catch the ThreadPoolExecutor the exact moment that it runs out of space is going to be very hard and it will quickly turn into a heisenbug in that the more you look at the ThreadPoolExecutor numbers, the more you are going to affect the synchronization of that class and therefore you might make the bug go away.

In your case, by the time you get to log the exception with the details about the TPE, the condition must have passed.

Gray
  • 115,027
  • 24
  • 293
  • 354
  • 1
    I appreciate the summary, but according to the error message I have 22 active threads and 0 queued threads. (I.e., less than 128 and 10.) Are you suggesting that the error message is reporting the wrong information somehow, or that I'm reading it wrong? – abeboparebop Oct 22 '13 at 22:35
  • I'm saying that the only way TPE throws a `RejectedExecutionException` is if it exceeds 128 and 10. You may only have 22 active at that moment but I suspect that it exceeded it because of a burst of traffic @abeboparebop. – Gray Oct 23 '13 at 13:02
  • 1. How do you know that `RejectedExecutionException` is only thrown in that case? I can't find any reference to it in the `AsyncTask` source code to which you linked. 2. How could I verify the 128 / 10 limits explicitly, given that the error message is giving misleading information? – abeboparebop Oct 25 '13 at 00:38
  • 1. I know because I've looked at the TPE code a lot @abeboparebop. What I'm _not_ sure of is the settings fort the `AsyncTask` with your version of Android. It may not be 128/10 limits but the only time the REE is thrown is from the `AbortPolicy` which is the default rejected handler. – Gray Oct 25 '13 at 16:24
  • 1
    I'm still bugged by the confusing message (we're not using a nonstandard version of Android or anything) but I'm going to accept this answer because this seems otherwise unambiguous. – abeboparebop Nov 05 '13 at 04:05
11

This exception also occur if your Executor call shutdown method and after that you give new Task (Runnable) for execution. Like

mThreadPoolExecutor.shutdown();
...
...
...
mThreadPoolExecutor.execute(new Runnable(){...});
Gabriella Angelova
  • 2,985
  • 1
  • 17
  • 30
Hafiz Waleed Hussain
  • 1,062
  • 12
  • 25
  • I faced this problem... if we call `shutDown()` or `shutDownNow()` then we need to again instantiate `mThreadPoolExecutor` like `mThreadPoolExecutor = Executors.newScheduledThreadPool(2);` – Kushal Nov 25 '15 at 15:08