5

I have a single thread pool ExecutorService object. At some time in the future tasks are added to be done using the submit() method. My understanding is that submit will submit add the submitted Runnable to the end of the list of tasks to be done. However I have a situation where based on a boolean I may want to submit the runnable to the front of the tasks to be executed. I don't want this to affect the current task, just that the next task done will be the one I just gave it. An example method is reproduced below. How do I do this?

Thanks

private ExecutorService singleLoadPool = Executors.newSingleThreadExecutor();
public void submitTask(Runnable run, boolean doNow) {
    if (doNow)
        singleLoadPool.submitFront(run);  // This is the method I'm looking for
    else
        singleLoadPool.submit(run);
}
Jon
  • 3,985
  • 7
  • 48
  • 80

2 Answers2

4

My preference would be use a LinkedBlockingDeque. It directly supports positional inserts/removes - putFirst(e)/takeFirst() and putLast(e)/takeLast() - which is your primary requirement- you dont have to implement a Comparator for your elements. Also this is bounded - which means that it provides safety against OutOfMemoryError.

edit In response to latest question :

First , have the ExecutorService like

ExecutorService executorService = new ThreadPoolExecutor(1, 1, 1, TimeUnit.SECONDS, workQueue);

Second , the important question is : what is the workQueue ?

The workQueue is a thin wrapper over any BlockingQueue implementation , which delegates all its methods to a LinkedBlockingDeque instance that it contains, except for the offer() method , which is called on it by the ThreadPoolExecutor and which needs to be overriden, like this :

       public boolean offer(E e) {
       if(doNow)
         return linkedBlockingDequeInstance.offerFirst(e);
      else 
         return linkedBlockingDequeInstance.offerLast(e);
   }

Ofcourse when you override any method - you need to careful to preserve thread safety and its general contract.Definitely this requires careful thought and rigorous testing.

Bhaskar
  • 7,443
  • 5
  • 39
  • 51
  • So I was just going to implement this and have one more question, how exactly do I add jobs to the queue? Do I have to override ThreadPoolExecutor since I can't just add Runnable objects to the LinkedBlockingDeque? – Jon Aug 02 '12 at 21:41
1

I think your best approach for this would be to instantiate a ThreadPoolExecutor with a PriorityBlockingQueue. Specifically, use a PriorityBlockingQueue constructor that takes in a Comparator. Your Comparator will be what you use to implement your 'priority'.

PriorityBlockingQueue<Runnable> workQueue = new PriorityBlockingQueue<Runnable>(20, yourPriorityComparator);
ExecutorService executorService = new ThreadPoolExecutor(1, 1, 1, TimeUnit.SECONDS, workQueue);
nicholas.hauschild
  • 42,483
  • 9
  • 127
  • 120
  • Thanks for the response, could you provide an example of a priorityComparator? – Jon Aug 01 '12 at 20:17
  • Take a look at the `Comparator` interface (now linked in the answer). You will likely need to implement your own `Comparator`, but it should be relatively straightforward. – nicholas.hauschild Aug 01 '12 at 20:24
  • My problem is that I don't understand how to get my boolean into the Comparator. In order to compile I need made a class with the following signature private class RunnableComparator implements Comparator. The Comparator needs to compare Runnable types and cannot compare classes that implement Runnable and there can only be 1 Comparator that needs to be instantiated before the ExecutorService can be instantiated, so the doNow boolean cannot be passed to it. – Jon Aug 01 '12 at 20:31