Reputation: 397
I am new to using Java thread pool. Now i have a use case for unit test when a new task comes and current thread number is max number and queue is full. I know in this case RejectedExecutionException
will be thrown. But how to best produce this scenario, what i can think of now is something like this:
LinkedBlockingQueue<Runnable> queue = new LinkedBlockingQueue<Runnable>(1);
ExecutorService ex = new ThreadPoolExecutor(2, 2, 60L, TimeUnit.MILLISECONDS, queue);
int rejected = 0;
try{
while (true){
ex.submit(() -> {
System.out.println("Queue remaining size: " + queue.remainingCapacity());
System.out.println("Thread amount in pool: " + ((ThreadPoolExecutor)ex).getPoolSize() + "\n");
});
}
}
catch (RejectedExecutionException e){
System.out.println(++rejected);
}
This is basic idea and i need to convert this using EasyMock if it is right way. I wonder if there is better way if using EasyMock instead of keep submitting task until thread and queue is full.
Upvotes: 2
Views: 1908
Reputation: 15622
You might move the execution code to a new class where you can easily mock out the dependencies:
class MyExecuter extends Executer{
private final ExecuterService executerService;
private final PrintStream out;
MyExecuter(ExecutorService executerService, PrintStream out){
this.executerService = executerService;
this.out = out;
}
@override
public void execute(Runnable r) {
int rejected = 0;
try{
while (true)
{
executerService.submit(() -> {
// do your business logic which usually does not care about the executor or the queue...
});
}
}
catch (RejectedExecutionException e)
{
out.println(++rejected);
}
}
}
Your code would change to this:
LinkedBlockingQueue<Runnable> queue = new LinkedBlockingQueue<Runnable>(1);
ExecutorService ex = new ThreadPoolExecutor(2, 2, 60L, TimeUnit.MILLISECONDS, queue);
Executor mex = new MyExcecutor(ex, System.out);
mex.execute();
Now you can create a Test for MyExcecutor
that gets mocks for ExecutorService
and PrintStream
so that you can verify interaction with them.
Upvotes: 0
Reputation: 116908
This is basic idea and i need to convert this using EasyMock if it is right way. I wonder if there is better way if using EasyMock instead of keep submitting task until thread and queue is full.
Anything that EasyMock would do would most likely take more code than your anonymous Runnable
. You could certainly do it but you would use an IAnswer
object instead of the Runnable
so I'm not sure it's much better.
The real question is what are you testing? Are you really making sure that the ThreadPoolExecutor
is doing it's job or are you really trying to mock out an ExecutorService
or as @Warren mentioned a ThreadPoolExecutor
.
I'd do a Thread.sleep(1000)
in your Runnable
and submit 4 of them instead of the while
loop. You can also create one object at the start and submit it multiple times. Please excuse the Java 7 code:
BlockingQueue<Runnable> queue = new LinkedBlockingQueue<>(1);
ExecutorService ex = new ThreadPoolExecutor(2, 2, 60L, TimeUnit.MILLISECONDS, queue);
Runnable runnable = new Runnable() {
@Override
public void run() {
try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); }
}
};
try {
ex.submit(runnable); // 1st thread
ex.submit(runnable); // 2nd thread
ex.submit(runnable); // 1st queued
ex.submit(runnable); // rejected
} catch (RejectedExecutionException e) {
System.out.println("rejected");
}
Upvotes: 1
Reputation: 38940
One simple solution:
Call shutdown before submitting the task.
If you call submit()
after shutdown(
), you will get this type of execption:
java.util.concurrent.RejectedExecutionException: Task MyRunnable@3dcc0a0f
rejected from java.util.concurrent.ThreadPoolExecutor
Upvotes: 0
Reputation: 8938
I'm not familiar with EasyMock in particular, but the general approach should be to mock out the ThreadPoolExecutor.
Upvotes: 1