I am writing a REST API in Java 7 to retrieve three items from database and send all three together to user as a response. When program runs in the sequential flow i.e. if I fetch one item then another then it is taking legitimate time for execution. But when I use multi-threading i.e. using three threads to fetch three items from database, it is taking more time for execution as compared to sequential. This issue is leading high CPU usage more than 90%.
example:
Sequential: number of users 60
average execution time- 5149 milliseconds
Parallel: number of users 60
average execution time- 9544 milliseconds
I am using ExecutorService to achieve asynchronous execution mechanism and Countdown latch for synchronization of threads.
Why parallel execution taking more time then sequential? Is there any drawback of using Countdown latch here?
Code for execution of worker threads using Countdown latch :
List<Runnable> workers;
if (StringUtils.isBlank(typeCode)) {
workers =
ItemManagerHelper.determineItemLookupWorkersByItemIdentifiers(Id, ids,
effectiveStartDate, effectiveEndDate, errors, ItemUIList, dataMap);
}
else {
workers = ItemManagerHelper.determineItemLookupWorkersByItemType(Id,
ids,effectiveStartDate,effectiveEndDate, typeCode, errors, ItemUIList,
dataMap);
}
ExecutorService threadPoolExecutor = Executors.newFixedThreadPool
(workers.size());
CountDownLatch latch = new CountDownLatch(workers.size());
for (Runnable worker : workers) {
((ItemLookupThread) worker).setLatch(latch);
threadPoolExecutor.submit(worker);
}
try {
latch.await(threadTimeOut, TimeUnit.MILLISECONDS);
}
catch (InterruptedException e) {
error(this.getClass(), e, "Exception occurred while waiting for the
lookup child threads completion.");
}
finally {
threadPoolExecutor.shutdown();
}
ItemLookupThread is my thread class:
public class ItemLookupThread implements Runnable {
private ItemProvider provider;
private long Id;
ItemsIdentifiers ids;
private long effectiveStartDate;
private long effectiveEndDate;
private Map<Object, Object> dataMap;
private List<BaseResponse.Error> errors;
private List<ItemUI> Items;
private CountDownLatch latch;
public ItemLookupThread (ItemProvider provider, long Id,
ItemsIdentifiers ids,long effectiveStartDate,
long effectiveEndDate, Map<Object, Object> dataMap,
List<ItemUI> Items, List<BaseResponse.Error> errors) {
this.provider = provider;
this.Id = Id;
this.ids = ids;
this.effectiveStartDate = effectiveStartDate;
this.effectiveEndDate = effectiveEndDate;
this.dataMap = dataMap;
this.Items = Items;
this.errors = errors;
}
@Override
public void run() {
try {
debug(this.getClass(), "Item lookup started :" +
Thread.currentThread().getId());
provider.lookup(Id, ids, effectiveStartDate, effectiveEndDate,
dataMap, Items, errors);
debug(this.getClass(), "Item lookup completed :" +
Thread.currentThread().getId());
}
finally {
if (latch != null) {
latch.countDown();
}
}
}
public void setLatch(CountDownLatch latch) {
this.latch = latch;
}
}