Java ExecutorService,避免任务队列过满的标准方法

Java ExecutorService,避免任务队列过满的标准方法,java,concurrency,Java,Concurrency,我正在使用ExecutorService,以简化并发多线程程序。以以下代码为例: while(xxx) { ExecutorService exService = Executors.newFixedThreadPool(NUMBER_THREADS); ... Future<..> ... = exService.submit(..); ... } 我确信有一个更好的更封装的解决方案?您最好自己创建一个(Executors.newXXX()

我正在使用
ExecutorService
,以简化并发多线程程序。以以下代码为例:

while(xxx) {
    ExecutorService exService = Executors.newFixedThreadPool(NUMBER_THREADS);
    ...  
    Future<..> ... = exService.submit(..);
    ...
}


我确信有一个更好的更封装的解决方案?

您最好自己创建一个(Executors.newXXX()就是这样做的)

在构造函数中,您可以传入一个BlockingQueue,供执行器用作其任务队列。如果传入一个大小受限的BlockingQueue(如),它应该会达到您想要的效果

ExecutorService exService = new ThreadPoolExecutor(NUMBER_THREADS, NUMBER_THREADS, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<Runnable>(workQueueSize));
ExecutorService exService=new-ThreadPoolExecutor(线程数,线程数,0L,TimeUnit.ms,new-LinkedBlockingQueue(workQueueSize));

您可以调用
ThreadPoolExecutor.getQueue().size()
以了解等待队列的大小。如果队列太长,您可以执行操作。如果队列太长,无法降低生产者的速度(如果合适的话),我建议在当前线程中运行任务。

一个真正的阻塞ThreadPoolExecutor已经出现在许多人的愿望列表上,甚至有一个JDC bug在上面打开。 我也面临同样的问题,遇到了这样的问题:


它是BlockingThreadPoolExecutor的实现,使用RejectionPolicy实现,该策略使用offer将任务添加到队列中,等待队列有空间。看起来不错

您可以添加另一个bloquing队列,该队列的大小有限,以控制executorService中内部队列的大小,有些人认为它类似于信号量,但非常简单。
在executor之前放置()以及任务何时完成()。take()必须位于任务代码内。诀窍是使用固定的队列大小和:

new ThreadPoolExecutor.CallerRunsPolicy()
我也推荐用番石榴。 以下是消费者/生产者队列的示例

private ListeningExecutorService producerExecutorService = MoreExecutors.listeningDecorator(newFixedThreadPoolWithQueueSize(5, 20));
private ListeningExecutorService consumerExecutorService = MoreExecutors.listeningDecorator(newFixedThreadPoolWithQueueSize(5, 20));

private static ExecutorService newFixedThreadPoolWithQueueSize(int nThreads, int queueSize) {
    return new ThreadPoolExecutor(nThreads, nThreads,
                                  5000L, TimeUnit.MILLISECONDS,
                                  new ArrayBlockingQueue<Runnable>(queueSize, true), new ThreadPoolExecutor.CallerRunsPolicy());
}
private-ListeningExecutorService producerExecutorService=more-executors.listeningDecorator(newFixedThreadPoolWithQueueSize(5,20));
私有ListingExecutorService consumerExecutorService=MoreExecutors.ListingDecorator(newFixedThreadPoolWithQueueSize(5,20));
专用静态执行器服务newFixedThreadPoolWithQueueSize(int-nThreads,int-queueSize){
返回新的ThreadPoolExecutor(第n个线程,第n个线程,
5000L,时间单位为毫秒,
新的ArrayBlockingQueue(queueSize,true),新的ThreadPoolExecutor.CallerRunPolicy();
}

<> P> >你可能想考虑一个MQ样的RabBMQ或ActuMeq,因为它们有QoS技术。

< P>我知道这太老了,但可能对其他开发者有用。因此,提交一份报告

正如您所要求的更好的封装解决方案。它是通过扩展ThreadPoolExecutor和重写submit方法来完成的


使用信号量实现的BoundedThreadpoolExecutor。当任务队列变满时,Java executor服务抛出RejectedExecutionException。使用无界队列可能会导致内存不足错误。这可以通过使用executor服务控制提交的任务数量来避免。这可以通过使用信号量或实现RejectedExecutionHandler来实现。

我明白了。我当时忽略了一个细节。这里提到,作为标准使用的是无界队列。我试过了。不幸的是,您的解决方案没有阻塞(正如我所希望的那样),而是抛出一个RejectedExecutionException。还发现:。所提出的解决方法似乎比我的信号量示例更复杂,该死!如果队列已满,则由于RejectedExecutionException而无法工作,因为它没有解决问题中的问题。同样,它也不会阻止,但会向另一个问题抛出拒绝。建议使用自定义
BlockingQueue
子类,该子类通过委托给
put()
来阻止
offer()
。我认为最终的效果与此
RejectedExecutionHandler
大致相同。答案很好,有完整的示例。
private ListeningExecutorService producerExecutorService = MoreExecutors.listeningDecorator(newFixedThreadPoolWithQueueSize(5, 20));
private ListeningExecutorService consumerExecutorService = MoreExecutors.listeningDecorator(newFixedThreadPoolWithQueueSize(5, 20));

private static ExecutorService newFixedThreadPoolWithQueueSize(int nThreads, int queueSize) {
    return new ThreadPoolExecutor(nThreads, nThreads,
                                  5000L, TimeUnit.MILLISECONDS,
                                  new ArrayBlockingQueue<Runnable>(queueSize, true), new ThreadPoolExecutor.CallerRunsPolicy());
}