Thursday, June 19, 2008

Deterministic unittests with ExecutorService

Java threadpool (ExecutorService) objects have some differences with .NET Threadpool:
- you can code to the ExecutorService interface
- you can call awaitTermination() to let all threads finish
- and you can use different thread pool objects, for example:

· Executors.newCachedThreadPool() is similar to .NET Threadpool where you let JVM manage the number of active threads. However, .NET Threadpool resists creating new threads (and rightfully so), while cached thread pool will create one on demand (according to Effective Java™, Second Edition.)
· Executors.newFixedThreadPool() let you control the number of thread.

While I usually default to a fixed thread pool, I think one should put code under stress to see which one is better and also allow for switching between two if underlying implementation change – code to the interface!

int numberOfThreads = //get from configs
if (numberOfThreads<=0){

executor = Executors.newCachedThreadPool();
}
else{
executor = Executors.newFixedThreadPool(numberOfThreads);
}

I use jmock a lot for unittests but quickly discovered that it is not threadsafe. I wanted deterministic execution of my unittests, but couldn’t give up on either Jmock or threadpool. I've read jmock faq on threads and got an idea to mock both threadpool and Future objects:

public class MockThreadPoolExecutorFixture implements ExecutorService {
private MockThreadPoolExecutorFixture(){}

public static ExecutorService getInstance(){
return new MockThreadPoolExecutorFixture();
}

@Override
public Future submit(Callable mytask){
MockFutureFixture myfuture = new MockFutureFixture(mytask);
return myfuture;
}
/*other API return default values of null or false – they were not used, feel free to override them as well if need be*/
}

public class MockFutureFixture implements Future {
private Callable mycall;
public MockFutureFixture(Callable arg0) {
mycall = arg0;
}

@Override
public V get() throws ExecutionException {
try{
return mycall.call();
}
catch (Exception e){
throw new ExecutionException(e);
}
}
/*other API return default values of null or false – they were not used, feel free to override them as well if need be*/
}
Of course, the next step is to stress the hell out of your code using real threadpool to see if you get thread synchronization problems.

2 comments:

Nat Pryce said...

Hi. The latest jMock code in Subversion contains an implementation of ScheduledExecutorService that does this and does scheduling too.

It will be in version 2.5.0, which will be released very soon.

Yuri said...

awesome! i'll check it out:)