刚开始看到这三个类,我看了很久也没看出它们的区别。先分别对其做个简短介绍。

先介绍一下三个类的共性,都是为了对JVM资源进行合理分配,并用线程池的特性也实现。

ThreadPoolTaskExecutor常用于项目中的异步任务处理,其UML关系如下:

 其配置如下:

@Configuration
@EnableAsync
public class AsyncConfiguration implements AsyncConfigurer{
    @Override
    public Executor getAsyncExecutor(){
        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
        executor.setCorePoolSize(5);
        executor.setMaxPoolSize(10);
        executor.setQueueCapacity(15);
        executor.setThreadNamePrefix("DailyBackup-");
        executor.initialize();
        return executor;
    }
}

 项目用法为:

@Service
@Async
public class AsyncServiceImpl {

    public void test(int i){
        try {
            System.out.println(i+"start");
            Thread.sleep(30000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println(i+"end");
    }
}

最后和普通的service用法一样,需要使用的时候注入IOC容器即可。这样就可以使用线程池的方式开启异步任务,简化多线程启动的同时,避免了系统资源的无序消耗。

 ScheduledThreadPoolExecutor 常用于项目中的异步任务处理,其UML关系如下:

其配置如下:

@Configuration
public class ScheduledConfiguration{
    @Bean
    public ScheduledThreadPoolExecutor scheduledThreadPoolExecutor(){
        return new ScheduledThreadPoolExecutor(5);
    }
}

 项目用法,在需要用到的地方直接注入即可。其在可以满足异步线程的同时,还可以满足延时执行任务,循环执行任务,常用方法有

scheduleAtFixedRate,scheduleWithFixedDelay

。其实从名字可以看出来,它首先是一个Executor的角色,之后再配置了一定的Scheduled定时执行任务的功能。

最后是 ThreadPoolTaskScheduler常用于项目中的带有定时计划的异步任务处理,其UML关系如下:

其使用可以直接从IOC容器获取:

@Autowired
private ThreadPoolTaskScheduler threadPoolTaskScheduler;

 但是由于其的主要任务是满足定时任务的需求,所以使用这个类的同时要在配置类,或者启动类加上@EnableScheduling注解,不然启动会报错。

有人会说,我们通常知道的@EnableScheduling注解和@Scheduled一起使用,就可以构造定时任务,为什么要引如这个ThreadPoolTaskScheduler来执行定时任务,其实归根结底,也是为了避免后期项目需求扩张以后出现的资源无序竞争、提高系统运行效率。

其示例demo如下:

@Override
    public void afterPropertiesSet() throws Exception {
        threadPoolTaskScheduler.setPoolSize(1);
        threadPoolTaskScheduler.schedule(new Runnable() {
            @SneakyThrows
            @Override
            public void run() {
                Thread.sleep(10000);
                System.out.println("测试111111111111111111111111111111");
            }
        }, new CronTrigger("0/10 * * * * *"));
        threadPoolTaskScheduler.schedule(new Runnable() {
            @SneakyThrows
            @Override
            public void run() {
                Thread.sleep(10000);
                System.out.println("测试22222222222222222222222222222222");
            }
        }, new CronTrigger("0/10 * * * * *"));

    }

可以看到在PoolSize为1的情况下,测试1和2任务只会有一个运行,另外的任务处于阻塞状态。

有时候,关于ScheduledThreadPoolExecutor和ThreadPoolTaskScheduler有点难以分辨,但是它们二者其实也是互斥的,两者在IOC容器中只能选择一个,其原因为:

public class TaskSchedulingAutoConfiguration {
    public TaskSchedulingAutoConfiguration() {
    }

    @Bean
    @ConditionalOnBean(
        name = {"org.springframework.context.annotation.internalScheduledAnnotationProcessor"}
    )
    @ConditionalOnMissingBean({SchedulingConfigurer.class, TaskScheduler.class, ScheduledExecutorService.class})
    public ThreadPoolTaskScheduler taskScheduler(TaskSchedulerBuilder builder) {
        return builder.build();
    }

通常我们会选择ThreadPoolTaskScheduler,因为其定时功能更强大一些。可以自定义trigger,而ScheduledThreadPoolExecutor的定时确没这么灵活。

Logo

为开发者提供学习成长、分享交流、生态实践、资源工具等服务,帮助开发者快速成长。

更多推荐