Spring Boot 对多线程支持

 Spring中实现多线程,其实非常简单,只需要在配置类中添加@EnableAsync就可以使用多线程。在希望执行的并发方法中使用@Async就可以定义一个线程任务。通过spring给我们提供的ThreadPoolTaskExecutor就可以使用线程池。

1. Spring Boot主类中定义一个线程池

定义线程池有两种方法,两种方法效果一样,细节略有区别。

1.1 方式一:实现AsyncConfigurer接口

@EnableAsync
@Configuration
public class CustomAsyncConfigurer1 implements AsyncConfigurer {
    private final Logger log = LoggerFactory.getLogger(CustomAsyncConfigurer.class);

    @Override
    @Bean(name = "taskExecutor")//如果系统只定义此一个线程池可以不加@Bean注解,定义多个线程池必须加@Bean注解。
    //@Qualifier("taskExecutor2")
    public Executor getAsyncExecutor() {
        log.debug("Creating Async Task Executor");
        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
        executor.setCorePoolSize(2); //核心线程数
        executor.setMaxPoolSize(5);  //最大线程数
        executor.setQueueCapacity(3); //队列大小
        executor.setKeepAliveSeconds(300); //线程最大空闲时间
        executor.setThreadNamePrefix("ics-Executor-"); 指定用于新创建的线程名称的前缀。
        executor.setRejectedExecutionHandler(
                new ThreadPoolExecutor.CallerRunsPolicy()); // 拒绝策略
        executor.initialize();
        return executor;
    }

    @Override
    public AsyncUncaughtExceptionHandler getAsyncUncaughtExceptionHandler() {
        return new SimpleAsyncUncaughtExceptionHandler();
    }
}

1.2 方式一:直接定义ThreadPoolTaskExecutor 类型的Bean

@EnableAsync
@Configuration
public class CustomAsyncConfigurer2 {
    private final Logger log = LoggerFactory.getLogger(CustomAsyncConfigurer1.class);


    @Bean(name = "taskExecutor2")//必须有@Bean注解
    //@Qualifier("taskExecutor2")
    public Executor getAsyncExecutor() {
        log.debug("Creating Async Task Executor");
        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
        executor.setCorePoolSize(10); //核心线程数
        executor.setMaxPoolSize(20);  //最大线程数
        executor.setQueueCapacity(1000); //队列大小
        executor.setKeepAliveSeconds(300); //线程最大空闲时间
        executor.setThreadNamePrefix("ics-Executor-"); 指定用于新创建的线程名称的前缀。
        executor.setRejectedExecutionHandler(
                new ThreadPoolExecutor.CallerRunsPolicy()); // 拒绝策略
        executor.initialize();
        return executor;
    }
}

2.springboot使用异步注解@Async

@Service
public class AsyncService {
    private static final Logger log = LoggerFactory.getLogger(AsyncService.class);

    @Autowired
    private ApplicationContext applicationContext;
    //@Autowired
    //@Qualifier("taskExecutor1")
   // @Resource(name = "taskExecutor1")
    private Executor threadPoolTaskExecutor;

    @Async
    public void asyncInvokeSimplest() {
        //Executor bean = applicationContext.getBean(ThreadPoolTaskExecutor.class);
        String[] beanNamesForType = applicationContext.getBeanNamesForType(Executor.class);

        try {
            log.info("asyncSimplest");
            Thread.sleep(30000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

3. 调用异步方法

@RestController
@RequestMapping("/async")
public class AsyncController {
    @Autowired
    private AsyncService asyncService;

    @GetMapping
    public void test(){
        for (int i = 0; i <20 ; i++) {
            asyncService.asyncInvokeSimplest();
        }

    }
}

知识点

1)调用异步方法 

  @Async
    public void asyncInvokeSimplest() 

必须通过Spring Bean 调用,不可内部调用。

2)如果 同时定义了 CustomAsyncConfigurer1  和 CustomAsyncConfigurer2 

@Async
    public void asyncInvokeSimplest()   调用此方法 会使用CustomAsyncConfigurer1(优先使用实现 AsyncConfigurer接口的,原因未知 )  的线程池

3)如果同时定义了多个线程池,如果想在异步方法中指定线程池,需在定义线程池的方法中加上@Bean("beanname") ,并指明bean 的name,同时@Async(“beananme”)
    public void asyncInvokeSimplest()  方法也要指定使用的beanname.

4) 如果想在程序中自动注入线程池,两种实现方式

  •  使用Qualifier 注解
@EnableAsync
@Configuration
public class CustomAsyncConfigurer2 {
    private final Logger log = LoggerFactory.getLogger(CustomAsyncConfigurer1.class);


    @Bean(name = "taskExecutor2")//必须有@Bean注解
    @Qualifier("taskExecutor2")
    public Executor getAsyncExecutor() {
        log.debug("Creating Async Task Executor");
        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
        executor.setCorePoolSize(10); //核心线程数
        executor.setMaxPoolSize(20);  //最大线程数
        executor.setQueueCapacity(1000); //队列大小
        executor.setKeepAliveSeconds(300); //线程最大空闲时间
        executor.setThreadNamePrefix("ics-Executor-"); 指定用于新创建的线程名称的前缀。
        executor.setRejectedExecutionHandler(
                new ThreadPoolExecutor.CallerRunsPolicy()); // 拒绝策略
        executor.initialize();
        return executor;
    }
}

@Service
public class AsyncService {
    private static final Logger log = LoggerFactory.getLogger(AsyncService.class);

    @Autowired
    private ApplicationContext applicationContext;
    @Autowired
    @Qualifier("taskExecutor2")
    private Executor threadPoolTaskExecutor;

    @Async
    public void asyncInvokeSimplest() {
        //Executor bean = applicationContext.getBean(ThreadPoolTaskExecutor.class);
        String[] beanNamesForType = applicationContext.getBeanNamesForType(Executor.class);

        try {
            log.info("asyncSimplest");
            Thread.sleep(30000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}
  • 使用@Resource注解

 

@EnableAsync
@Configuration
public class CustomAsyncConfigurer2 {
    private final Logger log = LoggerFactory.getLogger(CustomAsyncConfigurer1.class);


    @Bean(name = "taskExecutor2")//必须有@Bean注解
    public Executor getAsyncExecutor() {
        log.debug("Creating Async Task Executor");
        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
        executor.setCorePoolSize(10); //核心线程数
        executor.setMaxPoolSize(20);  //最大线程数
        executor.setQueueCapacity(1000); //队列大小
        executor.setKeepAliveSeconds(300); //线程最大空闲时间
        executor.setThreadNamePrefix("ics-Executor-"); 指定用于新创建的线程名称的前缀。
        executor.setRejectedExecutionHandler(
                new ThreadPoolExecutor.CallerRunsPolicy()); // 拒绝策略
        executor.initialize();
        return executor;
    }
}

@Service
public class AsyncService {
    private static final Logger log = LoggerFactory.getLogger(AsyncService.class);

    @Autowired
    private ApplicationContext applicationContext;

    @Resource(name = "taskExecutor2")//指定bean 的名称
    private Executor threadPoolTaskExecutor;

    @Async
    public void asyncInvokeSimplest() {
        //Executor bean = applicationContext.getBean(ThreadPoolTaskExecutor.class);
        String[] beanNamesForType = applicationContext.getBeanNamesForType(Executor.class);

        try {
            log.info("asyncSimplest");
            Thread.sleep(30000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Spring Boot 提供了一种方便的方式来处理大量数据,特别是在涉及到分批(Batching)或多线程场景时,它结合了Spring框架的强大功能和现代并发编程的最佳实践。以下是使用Spring Boot进行批量多线程处理数据的一种常见策略: 1. **使用Reactor或Stream API**:Spring Boot 5引入了对Reactor和Java Stream的支持,你可以创建流式API来处理数据,这种方式天然适合于批量操作。例如,你可以使用`Flux`或`PipedBuffer`来逐块读取和处理数据。 ```java Flux<DataItem> dataStream = dataRepository.findAllInBatches(batchSize); dataStream.parallel().subscribe(data -> processData(data)); ``` 2. **Spring Batch**:这是一个专门用于批处理任务的模块,可以在Spring Boot项目中集成。它可以让你编写易于维护的批处理作业,管理任务生命周期,包括调度、监控和回滚。 ```java @Bean public ItemReader<DataItem> itemReader() { // 创建数据源读取器 } @Bean public ItemProcessor<DataItem, DataItem> itemProcessor() { // 数据处理逻辑 } @Bean public Job job(JobBuilderFactory jobs, StepBuilderFactory steps) { return jobs.get("batchJob") .incrementer(new RunIdIncrementer()) .flow(step1(), step2(), ...) .end() .build(); } @Bean public Step step1(StepBuilderFactory steps) { return steps.get("step1") .<DataItem, DataItem>chunk(batchSize) .reader(itemReader()) .processor(itemProcessor()) .writer(someWriter()) .build(); } ``` 3. **使用ExecutorService**:利用Spring提供的`ThreadPoolTaskExecutor`,你可以创建一个线程池来并发执行多个数据处理任务。 ```java ExecutorService executor = Executors.newFixedThreadPool(10); List<DataItem> dataList = ...; dataList.stream().parallel().forEach(executor::submit, new Consumer<Runnable>() { public void accept(Runnable r) { r.run(); } }); ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值