views:

1267

answers:

4

I am implementing a thread pooling mechanism in which I'd like to execute tasks of varying priorities. I'd like to have a nice mechanism whereby I can submit a high priority task to the service and have it be scheduled before other tasks. The priority of the task is an intrinsic property of the task itself (whether I express that task as a Callable or a Runnable is not important to me).

Now, superficially it looks like I could use a PriorityBlockingQueue as the task queue in my ThreadPoolExecutor, but that queue contains Runnable objects, which may or may not be the Runnable tasks I've submitted to it. Moreover, if I've submitted Callable tasks, it's not clear how this would ever map.

Is there a way to do this? I'd really rather not roll my own for this, since I'm far more likely to get it wrong that way.

(An aside; yes, I'm aware of the possibility of starvation for lower-priority jobs in something like this. Extra points (?!) for solutions that have a reasonable guarantee of fairness)

A: 

Would it be possible to have one ThreadPoolExecutor for each level of priority? A ThreadPoolExecutor can be instanciated with a ThreadFactory and you could have your own implementation of a ThreadFactory to set the different priority levels.

 class MaxPriorityThreadFactory implements ThreadFactory {
     public Thread newThread(Runnable r) {
         Thread thread = new Thread(r);
         thread.setPriority(Thread.MAX_PRIORITY);
     }
 }
willcodejavaforfood
Thread priority isn't really important to me here; the tasks themselves will tend to execute reasonably quickly (the goal is to get them to ~50ms each) so thread scheduling is less of an issue. It's the priority of the tasks relative to each other that is at issue here.
Chris R
Do they have to be executed in a certain order?
willcodejavaforfood
There's no one, true order, no, but tasks that arrive later but are of a higher priority _should_ execute earlier than tasks that arrive later, but are of a lower priority. Again, with some guarantee of fairness to prevent starvation.
Chris R
Well submitting them through a PriorityQueue ought to make they sure they get executed in the right order so I dont quite follow why you cannot do that.
willcodejavaforfood
The thread pool executor service does not support prioritization of tasks, that's why. You don't get direct control of what type of object is placed on the queue.
Chris R
+1  A: 

At first blush it would seem you could define an interface for your tasks that extends Runnable or Callable<T> and Comparable. Then wrap a ThreadPoolExecutor with a PriorityBlockingQueue as the queue, and only accept tasks that implement your interface.

Taking your comment into account, it looks like one option is to extend ThreadPoolExecutor, and override the submit() methods. Refer to AbstractExecutorService to see what the default ones look like; all they do is wrap the Runnable or Callable in a FutureTask and execute() it. I'd probably do this by writing a wrapper class that implements ExecutorService and delegates to an anonymous inner ThreadPoolExecutor. Wrap them in something that has your priority, so that your Comparator can get at it.

Adam Jaskiewicz
That was my take, too, but here's the problem; the `Runnable` instances that are passed in to the priority queue are _not_ the tasks that I `submit` directly, they're wrapped in a `java.util.concurrent.FutureTask<V>` which of course is not sorted the same way. If I use `execute` -- which does not, for example, accept `Callable` -- then it throws my own objects in.
Chris R
Hmm, that complicates things. I figured there was something I was missing.
Adam Jaskiewicz
I'll say. I'm still beating away at it, but...Well, suffice to say it's a pain :)
Chris R
Adam, it appears that you are sitting right behind me, because that's what I just did.Now, it's worth noting that this does NOT solve starvation problems. I'm not really sure how to go about that, but it's something I'll have to consider.
Chris R
Well, you know what they say about great minds, eh? The starvation issue is complicated. The only thing I can think of, and it could get really messy, is to use some sort of aging algorithm whereby from time to time you increase the priority of all tasks, and somehow update the queue. Unfortunately, that is <a href="http://stackoverflow.com/questions/714796/priorityqueue-heap-update">easier said than done.</a>
Adam Jaskiewicz
Oh for crying out loud... http://stackoverflow.com/questions/714796/priorityqueue-heap-update
Adam Jaskiewicz
The logic being that if you increase the priority of ALL tasks, then heapify the queue, you aren't changing priority of existing tasks in relation to each other, but any tasks already in the queue get higher priority than new tasks being added to the queue. I can't see this being trivial to implement in a lock-free way, though...
Adam Jaskiewicz
A: 

Hi Chris

I am facing the same challenge which you had faced.Did you find any solution for this. If this din't worked what had you done to achieve the goal.

+2  A: 

the correct answer is here

http://binkley.blogspot.com/2009/04/jumping-work-queue-in-executor.html

Yes, it is. It is surprisingly difficult to do.
dmeister