问题陈述:


我有一个5000 ID指向数据库中的行。[可能超过5000]
每个Runnable在给定ID的情况下检索数据库中的行,并执行一些耗时的任务

public class BORunnable implements Callable<Properties>{

  public BORunnable(String branchID) {
    this.branchID=branchID;
  }

  public setBranchId(String branchID){
    this.branchID=branchID;
  }
  public Properties call(){
    //Get the branchID
    //Do some time consuming tasks. Merely takes 1 sec to complete

    return propObj;
  }
}

我将这些可运行对象提交给执行者服务。
为此,我需要创建并提交5000甚至更多可运行对象到executor服务。在我的环境中,这种可运行对象的创建可能会导致内存不足异常。
[假设5000只是一个例子]


因此,我想出了一种方法,如果您提供其他不同的方法,我将不胜感激:


创建了固定大小为10的线程池。

int corePoolSize = 10;
ThreadPoolExecutor executor = new ThreadPoolExecutor(corePoolSize,
    corePoolSize + 5, 10, TimeUnit.SECONDS,
    new LinkedBlockingQueue<Runnable>());

Collection<Future<Properties>> futuresCollection =
    new LinkedList<Future<Properties>>();

将所有branchID添加到branchIdQueue

Queue<String> branchIdQueue = new LinkedList<String>();
Collections.addAll(branchIdQueue, branchIDs);

我试图重用可运行的。创建了一堆可运行的

现在我希望将此数量的元素出队并为每个元素创建可运行

int noOfElementsToDequeue = Math.min(corePoolSize, branchIdQueue.size());

ArrayList<BORunnable>runnablesList = dequeueAndSubmitRunnable(
    branchIdQueue,noOfElementsToDequeue);


ArrayList<BORunnable> dequeueAndSubmitRunnable(branchIdQueue,
    noOFElementsToDequeue){
ArrayList<BORunnable> runnablesList= new ArrayList<BORunnable>();
    for (int i = 0; i < noOfElementsToDequeue; i++) {
        //Create this number of runnables
        runnablesList.add(new BORunnable(branchIdQueue.remove()));
    }
return runnablesList;
}

将检索到的可运行对象提交给执行者

for(BORunnable boRunnableObj:runnablesList){
     futuresCollection.add(executor.submit(boRunnableObj));
}

如果队列为空,则创建所需的可运行对象。如果不是,我想重用可运行对象并提交给执行者。
在这里,我得到可重用的可运行对象的数量=总计数-当前活动计数
[对我来说足够了]

int coreSize=executor.getCorePoolSize();

while(!branchIdQueue.isEmpty()){

    //Total size - current active count
    int runnablesToBeReused=coreSize-executor.getActiveCount();
    if(runnablesToBeReused!=0){
        ArrayList<String> branchIDsTobeReset = removeElementsFromQueue(
            branchIdQueue,runnablesToBeReused);
        ArrayList<BORunnable> boRunnableToBeReusedList =
            getBORunnableToBeReused(boRunnableList,runnablesToBeReused);
        for(BORunnable aRunnable:boRunnableList){
            //aRunnable.set(branchIDSTobeRest.get(0));
        }
    }

}



我的问题是


我无法找出线程池已释放了哪个Runnable,因此我可以使用它来提交
因此,我随机抽取了几个可运行对象并尝试设置branchId,但是随后可能发生线程竞争问题。 [不想使用挥发物]

最佳答案

重用Runnable没有意义,因为问题不在于创建或释放可运行实例的成本。这些在Java中几乎是免费提供的。

您要做的是限制易于实现的待处理作业的数量:只需限制要传递给执行者服务的队列。就像将int值(限制)传递给LinkedBlockingQueue’s constructor一样简单。请注意,您也可以使用ArrayBlockingQueue,因为LinkedBlockingQueue不能为有限队列使用提供优势。

在为队列提供限制后,执行者将拒绝排队新作业。剩下要做的唯一事情就是为执行者提供适当的RejectedExecutionHandler。例如。 CallerRunsPolicy足以避免在线程都繁忙且队列已满时调用方创建更多新作业。

执行后,Runnable受到垃圾回收。

10-01 01:55