I want to run a number of AsyncTask's on AsyncTask.THREAD_POOL_EXECUTOR.
I am using the following code.
Tasks[i].executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR,
taskParams);
After certain number of threads was sent to the executor, it no longer accepts new AsyncTasks. (I do not see any errors, but doInBackGroundMethod is not started for some reason).
I suspect this happens because it's pool is full.
Is there any way to reset the executor?
I want to completely terminate all the tasks so that it will start to accept new tasks again and process them immediately.
I tried to terminate the Tasks using their cancel method, but it didn't help.
Are your tasks finishing? Are you handling the apropriate exceptions? How many tasks are you creating?
Keep in mind that AsyncTask.THREAD_POOL_EXECUTOR (at least in API 17; this doc page has a bunch of useful details), is set up with
public static final Executor THREAD_POOL_EXECUTOR = new ThreadPoolExecutor(CORE_POOL_SIZE, MAXIMUM_POOL_SIZE, KEEP_ALIVE, TimeUnit.SECONDS, sPoolWorkQueue, sThreadFactory);
Where CORE_POOL_SIZE is 5 and MAXIMUM_POOL_SIZE is 128.
The sPoolWorkQueue with
private static final BlockingQueue<Runnable> sPoolWorkQueue = new LinkedBlockingQueue<Runnable>(10);
This means that the queue has a maximum capacity of 10 items.
The THREAD_POOL_EXECUTOR keeps at least 5 threads alive. As tasks are added, they are added to the queue. When the queue fills, then new threads will be spawned, up to 128 (there are other limitations tho).
When this happens (128 threads, the max, are running and the queue is full) then any new tasks will be rejected, and handled with the default handler (since it's not being set explicitly, is AbortPolicy), which throws a RejectedExecutionException.
Make sure that you're not just catching and not handling such exceptions.
One way to deal with this is to create your own ExecutorService (even if it's just your instance of ThreadPoolExecutor with different parameters) and configure the parameters that fit your situation best. Parameters like the queue (you can control the amount of items it can hold, or if it's unbounded, etc) or how to handle rejected tasks.
I can see two reasons to having cancelled AsyncTasks still running:
Either you don't call cancel with mayInterruptIfRunning set to true
Either you do call AsyncTask.cancel(true) but the InterruptedException is miss-handled by the executed code: Make sure your code (and the possible subsequent calls to libraries) don't obfuscate/silence InterruptedExceptions by a try/catch on InterruptedExceptions or even on Exception.
Related
I have been reading about Executor in Android documentations. If I understood it correctly, it is used for multiple thread management and it does some of the work for you like spawning new threads when needed. Or you may choose to manage stuff yourself.
In the example below, a group of executors are used instead of one. So it is something like a pool of pool of threads (?).
/**
* Global executor pools for the whole application.
*
* Grouping tasks like this avoids the effects of task starvation (e.g. disk
reads don't wait behind
* webservice requests).
*/
#Singleton
open class AppExecutors(
private val diskIO: Executor,
private val networkIO: Executor,
private val mainThread: Executor
) {
#Inject
constructor() : this(
Executors.newSingleThreadExecutor(),
Executors.newFixedThreadPool(3),
MainThreadExecutor()
)
fun diskIO(): Executor {
return diskIO
}
fun networkIO(): Executor {
return networkIO
}
fun mainThread(): Executor {
return mainThread
}
private class MainThreadExecutor : Executor {
private val mainThreadHandler = Handler(Looper.getMainLooper())
override fun execute(command: Runnable) {
mainThreadHandler.post(command)
}
}
}
Why would one choose to use a group of executors? What do you achieve with it which you can't with just one executor?
That's just structuring and assigning the right executor for the right jobs they might execute:
It's nicely put in a single class for easy reuse.
Three types of executors are employed, each for a specific type of task it could run. Remember that executors have threads to execute jobs or Runnables and each thread the executor creates can run one job at a time:
diskIO is (from the constrcutor) a Executors.newSingleThreadExecutor() since the tasks are best queued and executed one at a time to reduce write and read locks or race conditions for example. Hence a SingleThreadExecutor would run only one task at a time no matter how many are queued to ensure that design. Being a single thread could also mean that it's being used for writing app logs to a file for example which allows for the logs to be written in the proper order as being submitted to the executor. Hence single thread is best at maintaining output as in the order of jobs queued.
networkIO is a Executors.newFixedThreadPool(3) since the tasks are usually network related like connecting to a server on the internet and performing requests or getting data. These tasks usually make the user wait (could be between seconds to minutes) and need to be executed in parallel and fast to make the wait shorter in case many requests need be performed together. Hence the reason there are 3 threads employed with this executor is to assign the tasks among them and execute together. Order of jobs is not a concern here since jobs take different amount of time to execute but what matters the most is that they're running in parallel.
mainThread is a MainThreadExecutor() which in an Android app handles the UI and drawing it. The UI should function smoothly and not lag and hence the reason to use the above two executors is to let any heavy task (like writing a file or performing requests) to run in the background or separately from the mainThread of the app. This executor keeps performing tasks even if the app didn't submit any to it. The tasks it keeps performing is drawing the UI continuously on the screen which constantly repeats. Tasks executed by the mainThread need to lightweight and fast (time they take are in the order of milliseconds), and so any task that slows it down will be noticed as the UI will lag or glitch with it because the mainThread is busy finishing that task instead of drawing and updating the UI. The mainThread here simply uses a Handler which is part of the Android SDK/architecture, is of a single thread type and behaves like an executor (with some differences) that queues tasks to create/update the UI. Only a Handler can perform UI tasks, none of the other executors can.
I am using a threadpool with only one thread to execute some network tasks (They need to be executed sequentially)through a viewholder in a RecyclerView in Android. It is working, if I am scrolling slow. But if I am scrolling fast, too many tasks will be pushed to the queue, which I have discovered through debugging, is blocking the queue entirely.
I have simplified the code (much) where I am using the one threaded threadpool:
if (executorService == null) {
executorService = Executors.newFixedThreadPool(1);
}
executorService.execute(new Runnable() {
#Override
public void run() {
RessourceService.getCoverPage(url, callback);
while (waiting) {}
}
});
So what is the alternatives, if I want to execute network tasks sequentially without getting a blocked queue?
Have you tried using newSingleThreadExecutor()
public static ExecutorService newSingleThreadExecutor()
Creates an Executor that uses a single worker thread operating off an
unbounded queue.
(Note however that if this single thread terminates
due to a failure during execution prior to shutdown, a new one will
take its place if needed to execute subsequent tasks.)
Tasks are guaranteed to execute sequentially, and no more than one task will be
active at any given time. Unlike the otherwise equivalent
newFixedThreadPool(1) the returned executor is guaranteed not to be
reconfigurable to use additional threads.
(Posted answer on behalf of the question author).
The problem was somewhere else in my code and not in that posted in the question. As described in my question, I am executing the requests through a viewholder of a recyclerview. When scrolling fast, the images are not loaded. I found out that the problem was occurring when an item was out of sight in the recyclerview. The reason for this, was that the request was locked due to my "waiting" variable being true. I could solve it by making it static and setting it to false right before each request and thereby stopping the request in progress in another viewholder.
Nevertheless, the suggesting by #Jessie Brian Revil on using newSingleThreadExecutor, makes perfectly sense. Not a direct solution to my problem, but a reasonable solution for the code above (therefore accept).
I have a class called LoadEncryptedImage and that is derived from AsyncTask.
I used the below code to execute the async tasks in parallel,
LoadEncryptedImage loadEncryptedImage = new LoadEncryptedImage(mContext, eventMember.MemberPhotoURL,
viewHolder.imgUser);
loadEncryptedImage.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
It works properly, but it throws RejectedExecutionException if the tasks exceeds the limit of the ThreadPool. I want to set DiscardPolicy on ThreadPool to discard the issue silently. But how we can do this on a Threadpool created using ExecuteOnExecutor method.
But how we can do this on a Threadpool created using ExecuteOnExecutor method.
That is not a good idea. Do not change the characteristics of a thread pool that you did not create, as other things that depend upon that thread pool may not appreciate the changes that you make.
Instead, create your own ThreadPoolExecutor, with your desired characteristics, and pass that into executeOnExecutor().
does creating asyncTask like
AsyncTask<Void,Void,Void> newTask = new AsyncTask<Void,Void,Void>{
....
}
newTask.execute()
create memory leaks?
ok then #sherays Especially in Your case, If you execute another request to the server while previous one is not finished yet (in case of similar requests), this is a chance of memory leak.
Actually, there shouldn't be any issue with AsyncTask recycling unless You hold any reference to it from param or generate memory leaks inside doInBackground().
So, You might think, that if You're creating many long-running AsyncTasks then it would lead to some memory issues. Actually it's not true (at least on latest Android versions). AsyncTask source code shows that
It uses singleton bounded executor:
private static final int CORE_POOL_SIZE = 5;
private static final int MAXIMUM_POOL_SIZE = 128;
private static final int KEEP_ALIVE = 1;
public static final Executor THREAD_POOL_EXECUTOR
= new ThreadPoolExecutor(CORE_POOL_SIZE, MAXIMUM_POOL_SIZE, KEEP_ALIVE,
TimeUnit.SECONDS, sPoolWorkQueue, sThreadFactory);
That means that executor won't run more than 128 AsyncTasks the same time (128 is not very big per my understanding).
It uses bounded query for the Executor:
private static final BlockingQueue<Runnable> sPoolWorkQueue =
new LinkedBlockingQueue<Runnable>(10);
So, based on the above points, number of created and running the same time AsyncTasks are limited and not so big. So, if Your code inside AsyncTask doesn't create any memory leaks, then per my understanding there's no issue. Same time Android won't let You spam itself with AsyncTasks. Checkout ThreadPoolExecutors description to get familiar with the way it manages a memory (If You worry about too many created threads the same time).
so still,if you face memory leak then cancel the task:
Regarding cancel() call, based on Android documentation for AsyncTask:
Cancelling a task
A task can be cancelled at any time by invoking cancel(boolean). Invoking this method will cause subsequent calls to isCancelled() to return true. After invoking this method, onCancelled(Object), instead of onPostExecute(Object) will be invoked after doInBackground(Object[]) returns. To ensure that a task is cancelled as quickly as possible, you should always check the return value of isCancelled() periodically from doInBackground(Object[]), if possible (inside a loop for instance.)
Yes: is your thread garbage collected after onPostExecute is called or is it still in the memory?
An Async Task will not be canceled or destroyed at the moment the activity is dismissed. If your thread is more or less lightweight and finishes after a small time, just keep it running and add a yourActivity.this.isFinishing() clause in the onPostExecuteMethod.
I have an app, which uses several HTTPRequests for example
get a session id
get some locationdata
get existing categories
(...) and some more
I created a HTTPRequestHandler, which basically manages all the AsynTasks for each Request... This works well, but my problem is, I don't know a good way for managing the different AsynTasks. For example, you need to get the SessionId Task before you can start the GetSomeLocationData Task
So in my HTTPRequestHandler I have a queue, which starts the depending AsyncTasks like:
private void startSessionIdTask(...) {
//...
GetSessionIdTask mGetSessionIdTask = new GetSessionIdTask(this);
mGetSessionIdTask.execute(url);
}
//and from the postExecute() in GetSessionIdTask I call
public void setSessionId(int mSessionId) {
mDataHelper.setmSessionId(mSessionId); //set id
String url = API_URL + API_GET_FAVORITES + URL_VARIABLE;
List<NameValuePair> params = new LinkedList<NameValuePair>();
params.add(new BasicNameValuePair("session_id", getSessionId()));
String paramString = URLEncodedUtils.format(params, "utf-8");
url += paramString;
//and finally start another Tasks (and so one...)
GetLocationsTask mGetLocationsTask = new GetLocationsTask(this);
mGetSessionIdTask.execute(url);
}
However, this works fine, but the problem is, that (depending on the connection), this queue takes time, and the user can start other AsynTasks which fail, because some initially data is not loaded yet.
I could set some Boolean like isSessionIdLoaded or could block the UI for the user, but I'm wondering, if there s any better solution?!
So my question is: Is there a way to put asyntasks in some kind of queue (ArrayList, Map..) which will be executed in a row?
As of Android 3+ AsyncTasks will be executed in serial on the AsyncTask.SERIAL_EXECUTOR. So by default if you start 2 AsyncTasks
task1.execute();
task2.execute();
Task2 will only be executed if task1 has finished (just check the sdk implementaion of AsyncTask.SERIAL_EXECUTOR). This can be pushed to that point, that if task1 for any reason never finishes, task2 will never start and you have deadlocked your app.
If you want your own queue independed from the default SERIAL_EXECUTOR, just use
public final AsyncTask<Params, Progress, Result> executeOnExecutor (Executor exec, Params... params)
And provide your own executor (aka threadpool). For one project I copyed the SERIAL_EXECUTOR implementation to have 2 serial queues.
For Android 2.3 to 1.6 all tasks are by default in parallel, similiar to calling in Android 3+:
task.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR,null);
Unfortunatly in Android 2.3 und lower you have no option of specifing the executor on which the task/thread will be run on. So if you want to have it done serially, you have to implement it yourself, by calling task2 only after task1 has finished explicitly in onPostExecute(). This concept can of course be pushed to use a queue of task where the former task will call the next one when it's finished (= serial worker queue). For this you will find plenty literature and patterns.
I'm not entirely sure what you're asking, but if you'd just like a way to queue up Runnables to execute in a background thread in sequence, then Executors.newSingleThreadExecutor() may be what you're looking for. It's more complicated than it probably needs to be, but you can find examples and tutorials easily enough via google.
If you need sequential execution, I'd recommend switching to IntentService instead of using AsyncTask. See docs: http://developer.android.com/reference/android/app/IntentService.html