views:

2478

answers:

3

Hi,

I have an application which spawns a new thread when a user asks for an image to be filtered.

This is the only type of task that I have and all are of equal importance.

If I ask for too many concurrent threads (Max I ever want is 9) the thread manager throws a RejectedExecutionException.

At the minute what I do is;

// Manage Concurrent Tasks
private Queue<AsyncTask<Bitmap,Integer,Integer>> tasks = new LinkedList<AsyncTask<Bitmap,Integer,Integer>>();

@Override
public int remainingSize() {
 return tasks.size();
}

@Override
public void addTask(AsyncTask<Bitmap, Integer, Integer> task) {
 try{
  task.execute(currentThumbnail);
  while(!tasks.isEmpty()){
   task = tasks.remove();
   task.execute(currentThumbnail);
  }
 } catch (RejectedExecutionException r){
  Log.i(TAG,"Caught RejectedExecutionException Exception - Adding task to Queue");
  tasks.add(task);
 }
}

Simply add the rejected task to a queue and the next time a thread is started the queue is checked to see if there's a backlog.

The obvious issue with this is that if the final task gets rejected on its first attempt it will never be restarted (Until after it's no longer needed).

Just wondering if there's a simple model I should use for managing this sort of thing. I need tasks to notify the queue when they're done so I know there's space but I'm not sure how.

Kind regards,

Gavin

+1  A: 

You seem to have implemented a version of the Thread Pool design pattern -- the wikipedia article points to many helpful articles on the subject, which may help you refine your implementation. I also recommend this Java-specific article which has clear code and explanation.

Alex Martelli
+4  A: 

The reason for the RejectedExecutionException is because AsyncTask implements a thread pool of its own (per Mr. Martelli's answer), but one that is capped at a maximum of 10 simultaneous tasks. Why they have that limit, I have no idea.

Hence, one possibility is for you to clone AsyncTask, raise the limit (or go unbounded, which is also possible with LinkedBlockingQueue), and use your clone. Then, perhaps, submit the change as a patch to AsyncTask for future Android releases.

Click here to run a Google Code Search for AsyncTask -- the first hit should be the implementation.

If you just want to raise the limit, adjust MAXIMUM_POOL_SIZE to be as big as you're likely to need. If you want to go unbounded, use the zero-argument LinkedBlockingQueue constructor instead of the one being presently used. AFAICT, the rest of the code probably stays the same.

CommonsWare
The limit is not 10 anymore. The limit was put in place because AsyncTasks are not meant to be fired by the dozen. Since the goal of such a task is to update the UI, it would be pretty terrible to have dozens of threads causing updates.
Romain Guy
A: 

Maybe an option is to have the task wait on a blocking queue (of bitmaps) instead of taking bitmap as a parameter, but you will have to add a way for the task(s) to terminate.

tip