使用弹簧`@ Scheduled`和`@ Async`一起设计考虑因素

时间:2018-05-21 12:02:28

标签: spring multithreading scheduled-tasks spring-scheduled spring-async

我有一些关于一起使用Spring的@Scheduled@Async功能的问题。

让我说我的要求是每1秒从一个DB处理5行,所以在调度程序线程的1次传递中将创建5个异步线程 处理数据库中的每一行。

我的问题如下:

1)是否有另一种方法可以创建5个ascynchonis线程而不是在调度方法中使用while循环?

我看到这种方法的一个问题是线程池活动计数可能不等于最大池大小,因此循环在1秒之前不会中断。

2)在某些情况下,AsyncService中的日志语句,即Executing dbItem on the following asyncExecutor : task-scheduler-1显示task-scheduler-1作为线程名称,而不是async_thread_,因为我一直期望?

3)如果我的调度程序线程运行时间超过1秒,调度程序的后续传递会发生什么?

asyncExecutor:

@Override
@Bean(name="asyncExecutor")
public Executor getAsyncExecutor() {
    ThreadPoolTaskExecutor threadPoolTaskExecutor = new ThreadPoolTaskExecutor();        
    threadPoolTaskExecutor.setCorePoolSize(5);
    threadPoolTaskExecutor.setQueueCapacity(5);
    threadPoolTaskExecutor.setMaxPoolSize(10);
    threadPoolTaskExecutor.setThreadNamePrefix("async_thread_");
    threadPoolTaskExecutor.setWaitForTasksToCompleteOnShutdown(true);     
    return threadPoolTaskExecutor;
}

使用预定方法注入类:

@Autowired
@Qualifier("asyncExecutor")
private ThreadPoolTaskExecutor threadPoolTaskExecutor;

@Autowired
AsyncService asyncService;

@Autowired
private DaoService daoService;

@Scheduled(fixedRateString = "1000")
public void schedulerMetod() {

    try {       

        while (threadPoolTaskExecutor.getActiveCount() < threadPoolTaskExecutor.getMaxPoolSize()) {
            DbItem dbItem = daoService.retrieveNewItemFromDB();         
            if (dbItem != null){            
                asyncService.processNewItem(dbItem);
            }
        }

    } catch (ObjectOptimisticLockingFailureException ole){
        log.info(ole.getMessage());     
    } catch (Exception ex){
        log.error(ex.getMessage());
    }   
}


@Service
public class AsyncServiceImpl implements AsyncService {

    @Autowired
    private TaskService taskService;

    @Override
    @Transactional
    @Async("asyncExecutor")
    public void processNewItem(DbItem dbItem) {
        log.debug("Executing dbItem on the following asyncExecutor : " + Thread.currentThread().getName());     
        taskService.processNewItem(dbItem); 
    }

}

1 个答案:

答案 0 :(得分:0)

使用r1 == r2 bean,您将有双重目的,因为它同时实现了new PrimitiveWrapper()(支持ThreadPoolTaskScheduler)和TaskExecutor(支持@Async)两个接口。您可以这样配置:

TaskScheduler

如果提供另一个执行者名称,例如@Scheduled,则应在@Bean public ThreadPoolTaskScheduler taskScheduler() { ThreadPoolTaskScheduler threadPoolTaskScheduler = new ThreadPoolTaskScheduler(); threadPoolTaskScheduler.setPoolSize(5); threadPoolTaskScheduler.setThreadNamePrefix("async_thread_"); threadPoolTaskScheduler.initialize(); return threadPoolTaskScheduler; } 中提供执行者名称作为属性。 通过此实现,您已经对问题1和2有了答案。

关于第三个问题,如果线程池中的所有线程都处于繁忙状态,则调度程序将不执行任何操作,直到某个线程被释放,然后它将执行调度任务。您可能会考虑给线程池更大的大小。

最后但并非最不重要的是,仅使用taskScheduler1就足够了,因为它可以异步工作。