Java Concurrency Throttling。只允许一个请求

时间:2013-10-01 16:14:59

标签: java concurrency

我有长时间运行的代码,受到请求的影响,导致更高的资源使用率和不必要的并发问题。我的解决方案是像一个等待区域,每个线程等待一些预定义的时间。如果线程在等待时没有新请求,则继续执行该操作。任何新请求都会重新设置时钟,我们会释放前一个帖子。

之前我使用过信号量和倒计时锁存器,但它们都不适用于这种特定情况。在我编写代码之前,我想看看是否有一种标准的方法。

2 个答案:

答案 0 :(得分:5)

  

我有长时间运行的代码,受到请求的影响,导致更高的资源使用率和不必要的并发问题。

听起来你应该使用受限制的ExecutorService。您应该有一个固定数量的线程,并且每当有新请求进入时都会创建新线程。然后,您可以通过调整池中的线程数来最大化吞吐量。

// only allow 10 concurrent requests
ExecutorService threadPool = Executors.newFixedThreadPool(10);
...
while (requestsComeIn) {
    threadPool.submit(yourRunnableRequest);
}
// you need to shut the pool down once no more requests come in
threadPool.shutdown();

要限制请求,您应该使用RejectedExecutionHandler。类似下面的代码应该在队列中有100个元素后才能使用哪些块:

BlockingQueue<Runnable> queue = new ArrayBlockingQueue<Runnable>(100);
ThreadPoolExecutor threadPool =
      new ThreadPoolExecutor(10, 10, 0L, TimeUnit.MILLISECONDS, queue);
// we need our RejectedExecutionHandler to block if the queue is full
threadPool.setRejectedExecutionHandler(new RejectedExecutionHandler() {
       @Override
       public void rejectedExecution(Runnable r, ThreadPoolExecutor executor) {
           try {
                // this will block the producer until there's room in the queue
                executor.getQueue().put(r);
           } catch (InterruptedException e) {
                throw new RejectedExecutionException(
                   "Unexpected InterruptedException", e);
           }
    }
});
  

我的解决方案是拥有一个等待区域,每个线程等待一段预定义的时间。

您可以使用ThreadPoolExecutor免费获得此信息。例如,您可以分配1个核心线程和10个最大线程,然后指定(例如)5L, TimeUnit.MINUTES,因此如果5个额外线程中的一个休眠5分钟,它将被关闭。值得注意的是,遗憾的是,除非队列已满,否则ThreadPoolExecutor将不会比核心线程启动更多。因此,只有在队列中有100个内容之后才会分配第二个线程。出于这个原因,我通常使核心和最大线程参数值相同。

答案 1 :(得分:2)

保持控制的最简单方法是使用队列。现代BlockingQueue课程表现出色。然后,您可以通过改变队列的长度进行限制。

不是自己实际完成工作,而是将Job发布到队列中,让一个或多个线程位于队列的另一端,完成所有工作。

实际上有一个现成的结构用于实现这个精确的架构,它被称为ExecutorService。在其他地方有许多使用的例子。

有关详细信息,请参阅ExecutorService