Java 7并行执行没有使用Countdown latch

时间:2017-04-05 04:43:31

标签: java multithreading rest parallel-processing countdownlatch

我在Java 7中编写REST API以从数据库中检索三个项目,并将所有三个项目一起发送给用户作为响应。当程序在顺序流程中运行时,即如果我获取一个项目然后另一个项目,那么它将花费合法的时间来执行。但是当我使用多线程,即使用三个线程从数据库中获取三个项目时,与顺序相比,执行需要更多时间。此问题导致高 CPU使用率 超过90%。

示例:

     Sequential: number of users 60
                 average execution time- 5149 milliseconds

     Parallel:   number of users 60
                 average execution time- 9544 milliseconds

我使用ExecutorService来实现异步执行机制,使用倒计时锁存来实现线程同步。

为什么并行执行需要更多时间然后顺序执行?在这里使用倒计时锁存器有什么缺点吗?

使用倒计时锁存器执行工作线程的代码:

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是我的线程类:

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;
  }
}

1 个答案:

答案 0 :(得分:0)

我的猜测是有大量的上下文切换正在进行中。我的建议是将ExecutorService从方法变量移动到服务(或控制器)类中的字段。

private ExecutorService threadPoolExecutor = Executors.newFixedThreadPool(20);


public void myServiceMethod() {

    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);
        }
    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();
    }
}