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?
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.
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(){...});
Related
the rejectedexecutionexception occurs on app but does not point out from which action/thread/class its coming from. I have used nothing to manually shutdown threads or anything. But this is coming from coroutines
Fatal Exception: java.util.concurrent.RejectedExecutionException
Task java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask#eeb06f2 rejected from java.util.concurrent.ScheduledThreadPoolExecutor#75be143[Shutting down, pool size = 1, active threads = 0, queued tasks = 1, completed tasks = 0]
java.util.concurrent.ThreadPoolExecutor$AbortPolicy.rejectedExecution (ThreadPoolExecutor.java:2086)
java.util.concurrent.ScheduledThreadPoolExecutor.schedule (ScheduledThreadPoolExecutor.java:562)
a.a.b.a.b.d.c.a (c.java:4)
a.a.b.a.b.d.a.a (a.java:21)
a.a.b.a.b.b.a (b.java:5)
a.a.b.a.b.e.a.a (a.java:19)
a.a.b.a.c.e.a$c.invokeSuspend (a.java:6)
kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith (BaseContinuationImpl.java:33)
a.a.a.o0.run (o0.java:28)
a.a.a.c2.a$a.run (a.java:590)
I'm have a handler thread with thread priority set to background,
myHandlerThread = new HandlerThread(HANDLER_THREAD_NAME,
Process.THREAD_PRIORITY_BACKGROUND);
On this myHandlerThread I'm doing some operation to alter system property by invoking
SystemProperties.set(property, propertyValue);
I'm facing this exception frequently,
[Events]
java.lang.RuntimeException: failed to set system property
at android.os.SystemProperties.native_set(Native Method)
at android.os.SystemProperties.set(SystemProperties.java:130)
There can be multiple reasons which can cause this
1) The native code might have timed out when executing this code.
2) Since the thread is given with priority BACKGROUND it might not have time to execute when the CPU is busy and might have timed out at the end.
Will increasing the thread priority to NORMAL would help? Or how the thread will get timed out? Or what are the other reasons which could cause this issue?
myHandlerThread = new HandlerThread(HANDLER_THREAD_NAME,
Process.THREAD_PRIORITY_BACKGROUND);
Value of Process.THREAD_PRIORITY_BACKGROUND = 10
As you already know that in Java each thread has its own priority based on the thread which has created it. And we can change these priorities also like your above code.
By default, java provides priority scale between 0-10. But we can increase the scale by using Process.setThreadPriority() which provides scaling between (+/- 20).
Runnable r = ...
Thread thread = new Thread( new Runnable() {
public void run() {
android.os.Process.setThreadPriority(android.os.Process.THREAD_PRIORITY_MORE_FAVORABLE);
r.run();
}
});
So currently your above code is equivalent to Thread.setPriority() which only sets the handler thread priority to 10 (least in scale(0-10)).
I think the first one could be the reason which you had mentioned above:
1) The native code might have timed out when executing this code.
I am getting
java.util.concurrent.RejectedExecutionException: Task
android.os.AsyncTask$3#672f695 rejected from
java.util.concurrent.ThreadPoolExecutor#25293aa[Running, pool size =
17, active threads = 17, queued tasks = 128, completed tasks = 165].
How to resolve issue? Even i have just started 6-7 AsyncTask.
Let me know in which situations i can get above error.
I am running some async tasks and 1 of my users is crashing with a RejectedExecutionExemption:
Stack Trace
stackTrace: java.util.concurrent.RejectedExecutionException: Task android.os.AsyncTask$3#5e2675f rejected from java.util.concurrent.ThreadPoolExecutor#f5f25ac[Running, pool size = 9, active threads = 9, queued tasks = 128, completed tasks = 240]
at java.util.concurrent.ThreadPoolExecutor$AbortPolicy.rejectedExecution(ThreadPoolExecutor.java:2014)
at java.util.concurrent.ThreadPoolExecutor.reject(ThreadPoolExecutor.java:794)
at java.util.concurrent.ThreadPoolExecutor.execute(ThreadPoolExecutor.java:1340)
at android.os.AsyncTask.executeOnExecutor(AsyncTask.java:607)
The Line causing the exception
new SetDownloadStatusTask().executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
Two Part question here really..
I'd like like some help understanding the first line of the exception:
ThreadPoolExecutor#f5f25ac[Running, pool size = 9, active threads = 9, queued tasks = 128, completed tasks = 240]
pool size vs. active threads vs quad tasks.. I assume I am executing too many tasks, but am unsure how to determine this really for those three variables. If someone could break that down for me, Id appreciate it.
If this is the case that I am running out of threads, should I increase the amount allowed and if so how, or is there a better solution.
Custom AsyncTask
private class SetDownloadStatusTask extends AsyncTask<Void, Void, DownloadStatus> {
#Override
protected DownloadStatus doInBackground(Void... params) {
return bookDownloadManager.status(product);
}
#Override
public void onPostExecute(DownloadStatus downloadStatus) {
updateMenuForDownloadStatus(downloadStatus);
}
}
I assume I am executing too many tasks
Correct.
If someone could break that down for me, Id appreciate it
AsyncTask.THREAD_POOL_EXECUTOR, on a quad-core CPU, will support nine parallel threads (pool size = 9). That is backed by a LinkedBlockingQueue of maximum length 128. And, you have requested your 138th simultaneous task, so we are out of threads (active threads = 9) and the queue is full (queued tasks = 128).
should I increase the amount allowed and if so how, or is there a better solution
You should be asking yourself "why in the name of all that is holy am I trying to download 138 things at once?".
If there is a legitimate need for that, use your own custom Executor, rather than THREAD_POOL_EXECUTOR. If there is not a legitimate need for 138+ simultaneous downloads — and, frankly, that number seems insane — then change your code to avoid doing that, such as cancelling tasks that you no longer need.
I was testing AsyncTask details and stumbled on the issue that when I start muliple tasks, the tasks 6 to 15 (10 tasks always) are in status RUNNING, but do not get into doInBackground (where the start time is set). The next 100 tasks are started immediately.
(source: beadsoft.de)
The tasks are started pretty simple:
int tasksToStart = TASKS_TO_ADD_ON_CLICK;
while (tasksToStart > 0) {
tasksToStart--;
mTask = new MyTask(TASK_RUNNING_TIME);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB)
mTask.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
else
mTask.execute();
tvTaskInfo.setText("Task " + mTask.id + " requested.");
}
This leads to the situation that all later started tasks have to be finished (meaning total running tasks is less than 5) before tasks 5 actually starts doing something.
a) Is there a way to force start the tasks?
b) Why is the status RUNNING if it does not do anything. Should it not be PENDING?
I do not have an android 4.x real device and cannot test there. In the emulator same limitations apply.
Anyone interested can download this sample project here.
If you wish to run multiple AsyncTasks more than 5 (which is the default Executor limit), you need to start it with a different Executor, like this:
task.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
The THREAD_POOL_EXECUTOR Allows you to execute up to 15 parallel AsyncTasks, whereas SERIAL_EXECUTOR only allows up to 5, in serial order.