SpringBoot(一) 多线程与异步

多线程与异步

异步是目的,而多线程是实现这个目的的方法。

1 Java J.U.C线程调度

JDK 1.5新增的java.util.concurrent包,增加了并发编程的很多类。

image-20200707230102829

Executor

定义了方法execute(),用来执行一个任务

public interface Executor {

    void execute(Runnable command);

}

ExecutorService

提供了生命周期管理的方法。

submit()

shutdown()

invokeAll()

invokeAny()

ThreadPoolExecutor

Java提供的线程池类。可自定义线程池大小及线程处理机制。

corePoolSize:线程池的基本大小,即在没有任务需要执行的时候线程池的大小,并且只有在工作队列满了的情况下才会创建超出这个数量的线程。

maximumPoolSize:线程池中允许的最大线程数,线程池中的当前线程数目不会超过该值。

keepAliveTime:线程空闲时间

poolSize表示当前线程数,新提交一个任务时的处理流程为:

  • 如果当前线程池的线程数还没有达到基本大小(poolSize < corePoolSize),无论是否有空闲的线程新增一个线程处理新提交的任务

  • 如果当前线程池的线程数大于或等于基本大小(poolSize >= corePoolSize) 且任务队列未满时,就将新提交的任务提交到阻塞队列排队,等候处理。

  • 如果当前线程池的线程数大于或等于基本大小(poolSize >= corePoolSize) 且任务队列满时:

    • 当前poolSize<maximumPoolSize,那么就新增线程来处理任务
    • 当前poolSize=maximumPoolSize,那么意味着线程池的处理能力已经达到了极限,此时需要拒绝新增加的任务。至于如何拒绝处理新增的任务,取决于线程池的饱和策略RejectedExecutionHandler。

ScheduledExecutorService

定时调度接口。有4种调度机制:

//带延迟时间的调度,只执行一次,调度之后可通过Future.get()阻塞直至任务执行完毕

public ScheduledFuture<?> schedule(Runnable command, long delay, TimeUnit unit);

//带延迟时间的调度,只执行一次,调度之后可通过Future.get()阻塞直至任务执行完毕,并且可以获取执行结果

public <V> ScheduledFuture<V> schedule(Callable<V> callable, long delay, TimeUnit unit);

//带延迟时间的调度,循环执行,固定频率

public ScheduledFuture<?> scheduleAtFixedRate(Runnable command, long initialDelay, long period, TimeUnit unit);

//带延迟时间的调度,循环执行,固定延迟

public ScheduledFuture<?> scheduleWithFixedDelay(Runnable command, long initialDelay, long delay, TimeUnit unit);

ScheduledThreadPoolExecutor

基于线程池的定时调度实现。可以用来在给定延时后执行异步任务或者周期性执行任务。

ScheduledExecutorService4种调度机制的实现。

2 Spring线程调度

image-20200707232349760

TaskExecutor

Spring引入了TaskExecutor接口作为顶层接口。继承至J.U.C的Executor接口。

TaskScheduler

类似于J.U.C中的ScheduledExecutorService,是任务调度的接口。

功能与ScheduledExecutorService差不多,多了一个可传Trigger对象的schedule()方法,可支持Corn表达式进行任务调度。

ScheduledFuture<?> schedule(Runnable task, Trigger trigger);

ScheduledFuture<?> schedule(Runnable task, Date startTime);

ScheduledFuture<?> scheduleAtFixedRate(Runnable task, Date startTime, long period);

ScheduledFuture<?> scheduleAtFixedRate(Runnable task, long period);

ScheduledFuture<?> scheduleWithFixedDelay(Runnable task, Date startTime, long delay);

ScheduledFuture<?> scheduleWithFixedDelay(Runnable task, long delay);

AsyncTaskExecutor

接口中提供submit()方法执行任务。

ThreadPoolTaskExecutor

Spring提供的线程池类。与Java提供的ThreadPoolExecutor线程池类类似,可以配置线程池属性及拒绝策略。

处理流程与ThreadPoolExecutor一样。

ThreadPoolTaskScheduler

实现TaskScheduler接口,实现了其接口的调度机制。与Java中的ScheduledThreadPoolExecutor类类似。

多了一个可传Trigger对象的schedule()方法,可支持Corn表达式进行任务调度。

3 Spring异步操作

使用@Async注解

标注了@Async注解的方法,称之为异步方法。这些方法将在执行的时候,将会在独立的线程(线程池中获取)中被执行,调用者无需等待它的完成,即可继续其他的操作。

@Configuration

@EnableAsync

public class AsyncConfig {

}

@Async

public void downloadOrder() throws InterruptedException {

    System.out.println("执行开始时间为:" + LocalDateTime.now() + "线程为:" + Thread.currentThread().getName());

    Thread.sleep(10000);

    System.out.println("执行结束时间为:" + LocalDateTime.now() + "线程为:" + Thread.currentThread().getName());

}

@Async标注的方法,在同一个类中调用,无效

4 Spring定时任务的几个实现

4.1 基于@Scheduled注解

@Configuration //标记为配置类

@EnableScheduling //开启定时任务,可以放到启动类中

public class OrderScheduler {

    //定时任务执行周期,采用Corn表达式

    @Scheduled(cron = "0/5 * * * * ?")

    public void downloadOrder() {

        System.out.println("执行开始时间为:" + LocalDateTime.now() + "线程为:" + Thread.currentThread().getName());

        Thread.sleep(10000);

        System.out.println("执行结束时间为:" + LocalDateTime.now() + "线程为:" + Thread.currentThread().getName());

    }

}

//并不是每5秒执行一次,上次执行的结果会影响到下次运行。这个相当于10s运行一次了。

@Scheduled注解也可以直接指定时间间隔,如:@Scheduled(fixedRate=5000)

实现本质是基于Java中的ScheduledExecutorService类的schedule方法。

基于@Scheduled注解默认为单线程的。

标注了@Scheduled的方法,执行时是单线程的,也就是说,上次运行的结果会影响到下一次的执行。

image-20200706233720429

4.2 基于SchedulingConfigurer接口

@FunctionalInterface

public interface SchedulingConfigurer {

    void configureTasks(ScheduledTaskRegistrar taskRegistrar);

}

ScheduledTaskRegistrar类

实现SchedulingConfigurer接口,实现configureTasks方法,方法传入ScheduledTaskRegistrar类对象。

几种定时任务类型:

  • CronTask:根据Cron表达式执行定时任务
  • TriggerTask:按照Trigger触发器触发执行,可以动态改变定时任务的执行
  • FixedRateTask:固定速度执行
  • FixedDelayTask:固定延迟执行

@EnableScheduling //启动类,设置定时任务开关

@SpringBootApplication

public class MatrixApplication {

    public static void main(String[] args) {

        SpringApplication.run(MatrixApplication.class, args);

    }

}

@Component

public class TestScheduler implements SchedulingConfigurer {

    @Override

    public void configureTasks(ScheduledTaskRegistrar scheduledTaskRegistrar) {

        scheduledTaskRegistrar.addTriggerTask(() -> System.out.println("执行时间:" + LocalDateTime.now()), new CronTrigger("0/2 * * * * ?"));

    }

}

SchedulingConfigurer配置类比@Scheduled注解多了一个TriggerTask,更加灵活,其他的差不多。

4.3 基于注解设定多线程定时任务

@Scheduled注解默认为单线程的,我们可以使用@Async注解启用多线程。

@Configuration //标记为配置类

@EnableAsync //开启多线程

@EnableScheduling //开启定时任务,可以放到启动类中

public class OrderScheduler {

    //定时任务执行周期,采用Corn表达式

    @Async

    @Scheduled(cron = "0/5 * * * * ?")

    public void downloadOrder() {

        System.out.println("执行开始时间为:" + LocalDateTime.now() + "线程为:" + Thread.currentThread().getName());

        Thread.sleep(10000);

        System.out.println("执行结束时间为:" + LocalDateTime.now() + "线程为:" + Thread.currentThread().getName());

    }

}

image-20200706233756167

同一个任务的每一次定时任务执行,都会开辟一个新的线程,不会影响到下一次任务的执行。

4.4 ThreadPoolTaskScheduler

利用线程池实现任务调度。

@Resource 

private ThreadPoolTaskScheduler threadPoolTaskScheduler;
@GetMapping("/start")

public void test() {

    threadPoolTaskScheduler.schedule(() -> System.out.println("第" + i + "执行时间:" + LocalDateTime.now()), new CronTrigger("0/2 * * * * ?"));

}

4.5 整合Quartz

定时任务内部的方法可以结合@Async注解使用达到多线程的目的

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
引用\[1\]:在Spring Boot中实现多线程异步可以通过使用注解来实现。首先,在启动类上加上注解@EnableAsync,这样就开启了异步功能。然后,在想要异步执行的方法上加上注解@Async,表示该方法是异步的。最后,在主函数中调用该方法即可实现异步执行。Spring Boot真的很方便,只需要这两个注解就可以完成异步操作。\[1\] 引用\[2\]:另外,可以通过设置corePoolSize来控制线程池的大小,从而实现更好的线程管理。例如,将corePoolSize设置为10,重启Spring Boot后,可以使用Jmeter同时调用接口多次,观察控制台日志可以看到多个线程同时执行,这样可以提高程序的运行效率。\[2\] 总结起来,Spring Boot实现多线程异步的步骤如下: 1. 在启动类上加上注解@EnableAsync,开启异步功能。 2. 在想要异步执行的方法上加上注解@Async,表示该方法是异步的。 3. 在主函数中调用该方法即可实现异步执行。 4. 可以通过设置corePoolSize来控制线程池的大小,以优化线程管理。\[1\]\[2\] #### 引用[.reference_title] - *1* [springboot实现线程异步](https://blog.csdn.net/qq_38403590/article/details/119729294)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^control,239^v3^insert_chatgpt"}} ] [.reference_item] - *2* *3* [Springboot异步多线程编程](https://blog.csdn.net/baidu_28340727/article/details/122310314)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^control,239^v3^insert_chatgpt"}} ] [.reference_item] [ .reference_list ]

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值