ExecutorService应该在bean的整个生命周期中存活,或者应该具有狭窄(方法)范围

时间:2017-07-03 08:30:38

标签: java multithreading spring-boot executorservice

我有一个方法,必须处理数千个文档。

正常处理需要时间,所以我使用ExecutorService通过让多个线程并行工作来减少处理时间。

我必须使用此方法处理两个长列表。

  1. 处理ExecutorService的方法1:
  2. 现在,我已在方法中初始化ExecutorService并以相同方法关闭它。 (被叫两次)

    因此,它会导致创建和关闭ExecutorService两次。

      private List<DocDTO> convertData(args) {
        ExecutorService service = Executors.newFixedThreadPool(threads);
    
        List<Future<Set<DocDTO>>> futures = new ArrayList<Future<Set<DocDTO>>>();
    
        for (Pro pro : pros.getPros()) {
            Callable<Set<DocDTO>> callable = new Callable<Set<DocDTO>>() {
                public Set<DocDTO> call() throws Exception {        
                    for loop code
                }
            };
            futures.add(service.submit(callable));
        }
    
        service.shutdown();
        for (Future<Set<DocDTO>> future : futures) {
            if (future.get() != null) {
                list.addAll(future.get());
            }
        }   
    }   
    
    1. 处理ExecutorService的方法2:
    2. 我在看下面的链接:

      http://programtalk.com/java/executorservice-not-shutting-down/

      作者在班级创建了ExecutorService

      请您告诉我是否最好在方法级或班级创建ExecutorService

      仅供参考,上述代码中的方法每天执行两次

3 个答案:

答案 0 :(得分:1)

自然选择是将此类服务设为字段。

建立这样的服务不是免费的。你花了那笔费用来“构建”那个线程池;以及正确关闭它的时间 - 每次调用该方法时。

大多数时候,这不是你想要的。你想花一次时间(比如:当创建服务的对象被创建时)。

一个缺点:现在持有服务的班级的“生命时间”很重要。正如您现在可能必须担心显式调用shutdown()该持有者类所拥有的服务。

换句话说:当您不得不担心性能时,您可能会将服务更改为类的字段。

但是:你明确声明这个方法每天被调用两次。然后,您绝对不必担心通过创建/关闭该服务而生成的开销。即使开销会导致1秒的计算时间 - 每天2秒也根本不重要。

所以,鉴于 要求 - 我的(个人)建议:保持你的代码不变。在出现真正的问题之前,请勿触摸正在运行的系统。

答案 1 :(得分:1)

首先,我建议您阅读此doc,了解如何使用spring启用任务执行程序服务。正如GhostCat正确建议的那样,它应该在类级别。我还建议为它创建一个单独的bean。

例如:

@Bean
public TaskExecutor taskExecutor() {
    ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
    executor.setCorePoolSize(5);
    executor.setMaxPoolSize(10);
    executor.setQueueCapacity(25);
    return executor;
}

我是从this回答得到的,但是你可以在互联网上找到很多不同的配置。

答案 2 :(得分:0)

感谢Maleen和GhostCat的宝贵意见,我放弃了使用多线程的计划,原因有两个:

  • 从单线程和多线程运行时,我从同一方法得到不同的结果

  • ExecutorService不适用于Lazy关系。因此,将实体的负载从Lazy更改为Eager可能会影响其他功能性能

相反,我优化了加载实体的方式,而不是使用多线程。以前,我在for循环中逐个加载数据库中的所有静态数据并将其保存在EhCache中。

更改后,我使用findall方法一次性加载所有静态数据并保存在map中,并从for循环中的map中访问相同的数据。它大大提高了方法的性能。再次感谢你们两位。