ScheduledThreadPoolExecutor - 经常运行单个任务/线程或运行频率较低的多个线程

时间:2013-07-23 16:50:40

标签: java multithreading amazon-sqs threadpoolexecutor

我正在尝试设置一个每x分钟/秒/毫秒/无论如何运行的作业,并轮询Amazon SQS队列以处理要处理的消息。我的问题是最好的办法是什么。我应该创建一个带有x个线程的ScheduledThreadPoolExecutor并使用scheduleAtFixedRate方法调度单个任务,并且经常运行它(例如10毫秒),以便在需要时使用多个线程,或者,正如我向同事提议的那样,创建一个ScheduledThreadPoolExecutor具有x个线程,然后以稍微偏移的间隔创建多个计划任务,但运行频率较低。这对我来说听起来像是如何使用STPE。

通常我会使用Spring / Quartz来处理这种类型的事情,但这一点已经过时了。

那你有什么想法?

3 个答案:

答案 0 :(得分:1)

我建议您在SQS上使用long polling,这会使ReceiveMessage来电更像takeBlockingQueue的来电(这意味着您不会需要使用计划任务从队列中轮询 - 您只需要一个在无限循环中轮询的单个线程,如果连接超时则重试)

答案 1 :(得分:0)

这取决于任务的频率。如果您只需要及时轮询并且间隔不是很小,那么ScheduledThreadPoolExecutor scheduleAtFixedRate是一个不错的选择。

否则我会建议使用netty的HashedWheelTimer。在繁重的任务下,它可以提供最佳性能。 Akka和play使用它进行安排。这是因为STPE对于每个添加的任务都需要O(log(n)),其中HWT需要O(1)

如果你必须使用STPE,我会推荐一个任务,否则会导致资源过剩。

答案 2 :(得分:0)

长轮询就像一个阻塞队列,只有最大值20 seconds才会返回呼叫。如果这是轮询周期之间所需的最大延迟,则长轮询就足够了。除此之外,您还需要一个scheduledExector。

线程数实际上取决于您处理收到的消息的速度。如果您可以非常快速地处理消息,则只需要一个线程。我的设置如下

  1. SingleThreadScheduledExecutor scheduleWithFixedDelay在上一次完成后执行5分钟
  2. 在每次执行中,从SQS批量检索消息,直到没有更多消息要处理(请记住每个批次最多接收10条消息)。
  3. 处理消息,然后从队列中删除。
  4. 对于我的场景,单线程就足够了。如果积压增加(例如,每个可能涉及等待的消息需要网络操作),您可能希望使用多个线程。如果一个处理节点变得资源受限,则可以始终启动另一个实例(可能是EC2)以添加更多容量。