SpringBoot定时任务,@Async多线程异步执行

一、使用SpringBoot实现定时任务

这个不是重点,就简单的实现一下,至于cron表达式怎么写也不是重点,自行百度即可。

1-1、基于 @Scheduled 注解的方式
import org.springframework.scheduling.annotation.EnableScheduling;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;

@Component
@EnableScheduling
public class XdxOne {

    @Scheduled(cron = "*/1 * * * * ?")
    public void testOne(){
        System.out.println("one "  + " "+ Thread.currentThread().getName());
    }
}
1-2、基于SchedulingConfigurer接口实现
import org.springframework.scheduling.Trigger;
import org.springframework.scheduling.TriggerContext;
import org.springframework.scheduling.annotation.EnableScheduling;
import org.springframework.scheduling.annotation.SchedulingConfigurer;
import org.springframework.scheduling.config.ScheduledTaskRegistrar;
import org.springframework.scheduling.support.CronTrigger;
import org.springframework.stereotype.Component;

import java.util.Date;

@Component // 1.主要用于标记配置类,兼备Component的效果。
@EnableScheduling // 2.开启定时任务
public class XdxTestOne  implements SchedulingConfigurer {
    @Override
    public void configureTasks(ScheduledTaskRegistrar scheduledTaskRegistrar) {

        Runnable task = new Runnable() {
            @Override
            public void run() {
                Thread t = Thread.currentThread();
                String name = t.getName();
                System.out.println("XdxTestOne=" + name);
            }
        };
        Trigger trigger = new Trigger() {
            @Override
            public Date nextExecutionTime(TriggerContext triggerContext) {
            	// 这里我们可以通过去数据库获取cron表达式,从而实现动态
                CronTrigger trigger = new CronTrigger("*/3 * * * * ?");
                Date nextExec = trigger.nextExecutionTime(triggerContext);
                return nextExec;
            }
        };
        scheduledTaskRegistrar.addTriggerTask(task, trigger);
    }
}

上面两种方式都可以实现定时任务,毫无疑问注解方式实现起来更为舒服。但假如你不想把这个cron表达式写死,对于注解方式我们可能无可奈何(也可能是我没有找到方法)。但是对于接口的方式,我们可以在设置的时候去数据库获取,这样就实现了动态。

接口方式的定时任务每次执行的时候,都会去执行那个获取cron的方法。


二、异步实现

上面只是简单的实现了定时任务,一般来说也没有什么问题,但是上面的方式是一个线程挨个执行定时任务,这就会导致比如你某个线程是1s执行一次,但是你另外一个定时任务执行一次需要10min,那么你的这个定时任务就会被阻塞。
一般来说可能也不重要,因为只要最后执行就好了,但有时却是致命的,比我在工作中有一个定时任务是及时去同步数据来处理,这个时候阻塞了就是致命的。因此我们需要开启异步执行,也就是多线程执行,这样你一个定时任务阻塞了,还有另外的线程去执行我们的定时任务。

2-1、对于使用@Scheduled注解方式实现异步

我们可以使用 @Async 注解实现异步(异步方法使用注解@Async的返回值只能为void或者Future),把@Async加在类或者方法上面,然后还需要一个 @EnableAsync来开启异步。

@EnableAsync可以加在启动类上面这样可以直接开启所有的异步,也可以单独加在每个类上面。


2-1-1:版本差异

springBoot2.0 和 springBoot2.2 默认的线程池是不一样的,2.0默认线程池每开启一个新的任务都是新开一个线程的。2.2默认线程池有8个。
.
如果你的定时任务比较少,并且执行时间比较短其实上面两种都没啥关系。但是如果定时任务多且慢,那么2.0每次创建一个线程可能导致JVM挂掉,而2.2只有8个线程也会满足不了,会导致任务等待。


2-1-2:自定义线程池

创建一个线程池:

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import java.util.concurrent.ThreadPoolExecutor.CallerRunsPolicy;


@Configuration
@EnableAsync
public class AsyncConfig {
    
    @Bean(name = "taskExecutor")
    public ThreadPoolTaskExecutor asyncExecutor() {

        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
        // 核心线程数
        executor.setCorePoolSize(10);
        // 最大线程数
        executor.setMaxPoolSize(50);
        // 队列最大长度
        executor.setQueueCapacity(1000);
        // 线程池维护线程所允许的空闲时间
        executor.setKeepAliveSeconds(100);
        // 线程前缀
        executor.setThreadNamePrefix("AsyncExecutorThread-");
        // 线程池对拒绝任务(无线程可用)的处理策略
        executor.setRejectedExecutionHandler(new CallerRunsPolicy());
        executor.initialize();
        return executor;
    }
}

我们创建了上面的线程池后,所有的任务都将使用这个线程池里面的线程(可以通过输出线程名查看)

但是如果我们有多个线程池的时候,这个时候我们可以使用 @Async(“name”) name就是线程池的名字,没有写name的时候默认使用bean为taskExecutor 的线程池。


2-2、对于使用接口的方式实现异步

在这里插入图片描述
而对于使用注解的定时任务,如果你没有使用@Async注解给它指定线程池(可以理解默认name = taskExecutor,如果你没有taskExecutor线程池就会使用默认线程池),它也会使用接口里面创建的线程池进行调用。


三、其它

@EnableScheduling注解是开启定时任务的,随便放在那里都可以,只需要一个。

  • 3
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
Spring Boot中,可以使用@Scheduled注解来实现定时任务,可以结合@Async注解来实现多线程异步。 首先,需要在启动类上添加@EnableAsync注解,开启异步支持。然后在要执行异步任务的方法上添加@Async注解。 接下来,可以使用Java中的Executor框架来创建线程池,用于执行异步任务。可以在应用程序中创建一个线程池,并使用@Async注解将任务提交给线程池执行。 下面是一个示例代码: ```java @Configuration @EnableAsync public class AsyncConfig { @Bean(name = "taskExecutor") public Executor taskExecutor() { ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor(); executor.setCorePoolSize(10); executor.setMaxPoolSize(20); executor.setQueueCapacity(30); executor.setThreadNamePrefix("MyAsyncThread-"); executor.initialize(); return executor; } } @Service public class MyService { @Async("taskExecutor") @Scheduled(cron = "0 0 12 * * ?") //每天中午12点执行 public void myAsyncTask() { //异步任务内容 } } ``` 在上面的示例中,我们创建了一个名为“taskExecutor”的线程池,并将其注入到MyService中的myAsyncTask方法中。该方法使用@Async注解来指示它应该在异步线程中执行。@Scheduled注解指定了任务执行的时间。 需要注意的是,@Async注解只有在调用该方法的类通过Spring容器进行管理时才会生效。如果通过new关键字手动创建对象,@Async注解将不起作用。 希望这可以帮助你完成Spring Boot定时任务整合多线程异步的实现。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值