用于队列和工作者设计的实时执行器池

时间:2013-08-22 07:29:11

标签: java multithreading amazon-web-services message-queue

Rightnow,我正在尝试实现基于队列工作线的设计,我们在队列中收到数百万条消息。工人是有限的,所以我使用以下代码将工作分配给工人。我正在使用ExecutorService:

    ExecutorService pool = Executors.newFixedThreadPool(POOL_SIZE); 

    while(LISTEN_FOR_MESSAGE_FLAG == true){
      Message receivedMessage = sqsClient.receiveMessage(request);

      if(receivedMessage == null){
        Thread.sleep(5000); // sleep for 5 seconds
      }
      else {
        // lock the message for a certain amount of time (60 secs). 
        // Other workers can't receive a message, when it is locked.
        sqsClient.changeMessageVisibility(receivedMessage, 60); 

        pool.execute(new Task(receivedMessage); // process the message.
      }
    }

我目前正在使用Amazon SQS作为队列。上面的代码有严重的问题。它每5秒接收一次消息,并以可见性超时锁定它们。一旦可见性超时消失,此锁将被破坏。这导致工人持有不再被锁定的消息。因此,它存在重复处理的问题。 注意:Amazon SQS提供了一种扩展可见性超时的方法。

请帮助,如何编写上述代码来处理此案例。

1 个答案:

答案 0 :(得分:1)

如果你改变了

pool.execute(new Task(receivedMessage);

到:

Future<?> task = pool.submit(new Task(receivedMessage));

您可以执行辅助任务,在时间用完之前延长可见时间。辅助任务基本上对Future执行get(),超时时间小于60秒锁定。当发生TimeoutException时,它会扩展可见性超时,并再次开始等待Future。

pool.execute(new Runnable() {
    @Override
    public void run() {
        boolean done = false;
        while (!done) {
            try {
                task.get(50, TimeUnit.SECONDS);
                done = true;
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
                done = true;
            } catch (ExecutionException e) {
                done = true;
                // handle e.getCause()
            } catch (TimeoutException e) {
                // we need more time
                sqsClient.changeMessageVisibility(receivedMessage, 60);
            }
        }

    }
});