Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/353.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/spring/13.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 带线程池执行器的SQSListener_Java_Spring_Amazon Web Services_Spring Cloud_Amazon Sqs - Fatal编程技术网

Java 带线程池执行器的SQSListener

Java 带线程池执行器的SQSListener,java,spring,amazon-web-services,spring-cloud,amazon-sqs,Java,Spring,Amazon Web Services,Spring Cloud,Amazon Sqs,在下面的示例中,我将最大和核心池大小设置为1。但是,未处理任何消息。当我启用调试日志时,我能够看到从SQS中提取的消息,但我猜它没有被处理/删除。但是,当我将core和max pool size增加到2时,消息似乎已被处理 编辑 我相信Spring可能会为从队列中读取数据的接收方分配一个线程,因此它无法将线程分配给正在处理消息的侦听器。当我将corepoolsize增加到2时,我看到消息正在从队列中读取。当我添加另一个侦听器(用于死信队列)时,我遇到了相同的问题-2个线程不够,因为消息没有被处理

在下面的示例中,我将最大和核心池大小设置为1。但是,未处理任何消息。当我启用调试日志时,我能够看到从SQS中提取的消息,但我猜它没有被处理/删除。但是,当我将core和max pool size增加到2时,消息似乎已被处理

编辑

我相信Spring可能会为从队列中读取数据的接收方分配一个线程,因此它无法将线程分配给正在处理消息的侦听器。当我将corepoolsize增加到2时,我看到消息正在从队列中读取。当我添加另一个侦听器(用于死信队列)时,我遇到了相同的问题-2个线程不够,因为消息没有被处理。当我将corepoolsize增加到3时,它开始处理消息。我假设在本例中,分配了1个线程从队列中读取消息,并为2个侦听器分别分配了1个线程

@Configuration
public class SqsListenerConfiguration {

    @Bean
    @ConfigurationProperties(prefix = "aws.configuration")
    public ClientConfiguration clientConfiguration() {
        return new ClientConfiguration();
    }


    @Bean
    @Primary
    public AWSCredentialsProvider awsCredentialsProvider() {

        ProfileCredentialsProvider credentialsProvider = new ProfileCredentialsProvider("credential");
        try {
            credentialsProvider.getCredentials();
            System.out.println(credentialsProvider.getCredentials().getAWSAccessKeyId());
            System.out.println(credentialsProvider.getCredentials().getAWSSecretKey());

        } catch (Exception e) {
            throw new AmazonClientException(
                    "Cannot load the credentials from the credential profiles file. " +
                            "Please make sure that your credentials file is at the correct " +
                            "location (~/.aws/credentials), and is in valid format.",
                    e);
        }
        return credentialsProvider;
    }


    @Bean
    @Primary
    public AmazonSQSAsync amazonSQSAsync() {
        return AmazonSQSAsyncClientBuilder.standard().
                withCredentials(awsCredentialsProvider()).
                withClientConfiguration(clientConfiguration()).
                build();
    }


    @Bean
    @ConfigurationProperties(prefix = "aws.queue")
    public SimpleMessageListenerContainer simpleMessageListenerContainer(AmazonSQSAsync amazonSQSAsync) {
        SimpleMessageListenerContainer simpleMessageListenerContainer = new SimpleMessageListenerContainer();
        simpleMessageListenerContainer.setAmazonSqs(amazonSQSAsync);
        simpleMessageListenerContainer.setMessageHandler(queueMessageHandler());
        simpleMessageListenerContainer.setMaxNumberOfMessages(10);
        simpleMessageListenerContainer.setTaskExecutor(threadPoolTaskExecutor());
        return simpleMessageListenerContainer;
    }


    @Bean
    public QueueMessageHandler queueMessageHandler() {
        QueueMessageHandlerFactory queueMessageHandlerFactory = new QueueMessageHandlerFactory();
        queueMessageHandlerFactory.setAmazonSqs(amazonSQSAsync());
        QueueMessageHandler queueMessageHandler = queueMessageHandlerFactory.createQueueMessageHandler();
        return queueMessageHandler;
    }


    @Bean
    public ThreadPoolTaskExecutor threadPoolTaskExecutor() {
        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
        executor.setCorePoolSize(1);
        executor.setMaxPoolSize(1);
        executor.setThreadNamePrefix("oaoQueueExecutor");
        executor.initialize();
        return executor;
    }


    @Bean
    public QueueMessagingTemplate messagingTemplate(@Autowired AmazonSQSAsync amazonSQSAsync) {
        return new QueueMessagingTemplate(amazonSQSAsync);
    }


}
侦听器配置

    @SqsListener(value = "${oao.sqs.url}", deletionPolicy = SqsMessageDeletionPolicy.ON_SUCCESS)
    public void onMessage(String serviceData, @Header("MessageId") String messageId, @Header("ApproximateFirstReceiveTimestamp") String approximateFirstReceiveTimestamp) {

        System.out.println(" Data = " + serviceData + " MessageId = " + messageId);

        repository.execute(serviceData);
}

通过将
corePoolSize
maximumPoolSize
设置相同,可以创建
固定大小的线程池。记录了对规则的非常好的解释

设置
maxPoolSize
隐式允许删除任务。 但是,默认队列容量是
整数.MAX_值
,实际上,它是无穷大的

需要注意的是,
ThreadPoolTaskExecutor
在下面使用了一个
ThreadPoolExecutor
,它有一种不寻常的排队方法,如中所述:

如果
corePoolSize
或多个线程正在运行,那么执行器总是倾向于将请求排队,而不是添加新线程

这意味着
maxPoolSize
仅在队列已满时才相关,否则线程数将永远不会超过
corePoolSize
。 例如,如果我们向线程池提交从未完成的任务

  • 第一次提交的
    corePoolSize
    将分别启动一个新线程
  • 之后,所有提交的文件都进入队列
  • 如果队列是有限的,且其容量已耗尽,则每次提交都会启动一个新线程,最大可达
    maxPoolSize
  • 当池和队列都已满时,新提交将被拒绝
排队-阅读

任何
BlockingQueue
都可用于传输和保存提交的任务。此队列的使用与池大小交互:

  • 如果运行的线程少于corePoolSize,则执行器始终 更喜欢添加新线程而不是排队
  • 如果corePoolSize或多个线程正在运行,则执行器始终 更喜欢对请求排队,而不是添加新线程
  • 如果请求无法排队,则会创建一个新线程,除非 这将超过maximumPoolSize,在这种情况下,任务将 被拒绝
无限队列
。使用无界队列(例如
LinkedBlockingQueue
没有预定义的容量)将导致新的 在所有corePoolSize线程都繁忙的情况下要排队的任务。 因此,不会创建超过
corePoolSize
的线程。(及 因此,
maximumPoolSize
的值没有任何影响。)

  • 如果线程数小于
    corePoolSize
    ,则创建一个新的 线程以运行新任务
  • 如果线程数等于(或大于)
    corePoolSize
    ,将任务放入队列
  • 如果队列已满,且线程数小于
    maxPoolSize
    ,创建一个新线程以在其中运行任务
  • 如果队列已满,且线程数大于或 等于
    maxPoolSize
    ,拒绝该任务

  • 谢谢@Vikram Palakurthi。在我的示例中,我没有设置队列容量。所以我相信它是无限的。因此,我假设的maxpoolsize不相关。我尝试将大约10条消息推送到SQS FIFO队列。因为corepoolsize设置为1,所以我假设使用者将逐个处理消息。但是消费者没有获取消息。但是,当我将其设置为2时,消息正在被读取。是否有一个线程始终专用于轮询消息,因此如果我将队列大小设置为2,则第二条消息正在进行处理?否,不适用于轮询,但我猜在您的示例中是executor.setCorePoolSize(1);执行器setMaxPoolSize(1);第四条规则正在应用,任务将被拒绝。如果您看到规则的顺序,我猜执行器会检测到线程大于maxPoolSize,即1,并拒绝任务,这解释了为什么将其增加到2时处理工作正常。通过将corePoolSize和maximumPoolSize设置为相同,您创建了一个固定大小的线程池,让它无法动态分配不断增长的线程。尝试删除此部件执行器。setMaxPoolSize(1);我想只有当队列容量达到时,maxpoolsize才会生效。这甚至在您的回答中也有说明-“这意味着maxPoolSize仅在队列已满时才相关”。在我的情况下,我只是向队列发送4-5条消息以进行测试。我还尝试将maxpoolsize增加到1。但这种配置不会产生任何影响。只有当我将core pool size增加到大于1时,它才起作用。正确,在您的情况下core pool size为1,因为您有大约4-5条消息,所以maxPoolSize将生效。因为您将corePoolSize和maxPoolSize都设为1,这导致了问题。您提到您尝试将maxPoolSize增加到1,但这并不能解决您的问题,尝试将其增加到任何大于1的值,如2-5。这是我为这个问题创建的票证-