【问题标题】:ScheduledExecutorService inside a Spring Bean, not working after a couple of executionsSpring Bean中的ScheduledExecutorService,在几次执行后不起作用
【发布时间】:2020-06-03 01:52:15
【问题描述】:

我正在尝试在 Spring @Bean 中安排一个任务,该任务将更新从 Bean 返回的实例的属性。

我可以运行这段代码,执行器运行了几次,但之后突然停止加载。

这里到底有什么问题?有没有更好的方法来解决这个问题??

@Bean(name="service")
public Service getService(){
  Service service = new Service();
  ScheduledExecutorService serviceLoader = Executors.newScheduledThreadPool(1);
    serviceLoader.scheduleAtFixedRate(new Runnable() {
        @Override
        public void run() {
            service.loadAllLiveEvents();
        }
    }, 0, 1, TimeUnit.HOURS);

  return service;
}

【问题讨论】:

    标签: java spring multithreading spring-bean scheduledexecutorservice


    【解决方案1】:

    serviceLoader 的生命周期看起来很奇怪——它在方法或服务期间被初始化,然后安排一些工作,然后返回服务。对这个池的引用会发生什么?什么时候可以调用关机?

    此外,第一次迭代会立即运行,这会在应用程序上下文尚未准备好时发生,这可能会导致不可预知的结果,具体取决于迭代期间运行的实际代码。

    我无法确定基于此代码 sn-p 会发生什么,但这里有一些可能的解决方案:

    1. 使用@Scheduled注解,运行定时任务是spring内置的特性。教程很多,这里是one of them

    2. 如果一定要使用线程池,建议如下配置:

    @Configuration
    public class MyConfiguration {
       @Bean 
       public Service service() {
          return new Service();
       }
       @Bean(destroyMethod="shutdownNow") // or shutdown - now spring will close the pool when the app context gets closed
       @Qualifier("serviceLoaderPool") 
       public ScheduledExecutorService serviceLoader() {
            return Executors.newScheduledThreadPool(1);
       }
    
       @EventListener
       public void onAppContextStarted(ApplicationReadyEvent evt) {
           ScheduledExecutorService loader = 
           (ScheduledExecutorService)evt.getApplicationContext().getBean("serviceLoaderPool");
           Service service = evt.getApplicationContext.getBean(Service.class);
           loader.scheduleAtFixedRate(new Runnable() {
               @Override
               public void run() {
                   service.loadAllLiveEvents();
               }
           }, 0, 1, TimeUnit.HOURS);
       }
    }
    

    通过这种方法,您可以确保服务将在应用程序上下文准备就绪时开始刷新。

    executor 服务的生命周期也被明确定义,spring 将其作为常规的单例 bean 进行管理,因此只要应用程序上下文启动并运行,它就不会被 GC。

    destroy 方法的存在保证了优雅的关闭(同样,spring 会为你调用它)。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-10-04
      • 2023-03-20
      • 1970-01-01
      • 2016-06-03
      相关资源
      最近更新 更多