The problem occurs because you're task queue is too small and this is indicated by the documentation of the execute method:
Executes the given task sometime in the future. The task may execute in a new thread or in an existing pooled thread. If the task cannot be submitted for execution, either because this executor has been shutdown or because its capacity has been reached, the task is handled by the current RejectedExecutionHandler.
So the first problem is that you're setting your queue size to a very small number:
int poolSize = 2;
int maxPoolSize = 3;
ArrayBlockingQueue<Runnable> queue = new ArrayBlockingQueue<Runnable>(2);
And then you state "If [I] try 7th, 8th... task" then you would get a RejectedExecutionException
because you're past the capacity of the queue. There are two ways to resolve your problem (I would recommend doing both):
- Increase the size of the queue.
- Catch the exception and re-try adding the task.
You should have something along the lines of this:
public void ExecuteTask(MyRunnableTask task) {
bool taskAdded = false;
while(!taskAdded) {
try {
executor.execute(task);
taskAdded = true;
} catch (RejectedExecutionException ex) {
taskAdded = false;
}
}
}
Now, to address your other questions...
Here then what is the role of BlockingQueue if it is missing the tasks?
The role of the BlockingQueue
is to complete the Producer/Consumer pattern and if it's large enough, then you shouldn't see the issues you're encountering. As I mentioned above, you need to increase the queue size and catch the exception then retry executing the task.
Why cant we go for linkedlist?
A linked list is neither thread safe, nor is it blocking. The Producer/Consumer pattern tends to work best with a blocking queue.
Update
Please don't be offended by the following statements, I'm intentionally using more stringent language in order to put emphasis on the fact that your first assumption should never be that there is something wrong with the library you're using (unless you wrote the library yourself and you know that there is a specific problem in it)!
So let's put this concern to rest right now: neither the ThreadPoolExecutor
nor the Java library are the problem here. It's entirely your (mis)use of the library that's causing the problem. Javmex has a great tutorial explaining the exact situation you're seeing.
There could be several reasons why you're filling up the queue faster than you're emptying it:
- The thread that's adding tasks for executing is adding them too fast.
- The tasks are taking too long to execute.
- Your queue is too small.
- Any combination of the above 3.
There are a bunch of other reasons too, but I think the above would be the most common.
I would give you a simple solution with an unbounded queue, but it would NOT resolve your (mis)use of the library. So before we go blaming the Java library, let's see a concise example that demonstrates the exact problem you're encountering.
Update 2.0
Here are a couple of other questions addressing the specific problem:
- ThreadPoolExecutor Block When Queue Is Full?
- How to make ThreadPoolExecutor's submit() method block if it is saturated?