SpringBoot使用内置多线程

本文介绍了在SpringBoot中实现多线程的步骤,包括自定义线程池配置类并启用@EnableAsync注解,以及在异步方法上使用@Async注解。针对异步线程未生效的问题,分析了可能的原因,如缺少@EnableAsync注解、返回类型限制以及未通过Spring的代理类调用。并提供了解决方案,包括确保方法为public,从外部调用或通过获取代理类来调用。
摘要由CSDN通过智能技术生成

我们不生产代码,我们只是代码的搬运工。。。

在springboot中,只需如下两步实现多线程:
1.自定义线程池的配置类,并在类上添加@EnableAsync 注解,

package com.gxcards.common.executor;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
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.Executor;
import java.util.concurrent.ThreadPoolExecutor;

/**
 * @author cq
 * @date 2019/11/12
 * @descrption 线程池初始化
 * version 1.0
 */
@Configuration
@EnableAsync
public class ExecutorConfig {
    private static final Logger logger = LoggerFactory.getLogger(ExecutorConfig.class);
    @Bean
    public Executor asyncServiceExecutor() {
        logger.info("start asyncServiceExecutor");
        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
        //配置核心线程数
        executor.setCorePoolSize(10);
        //配置最大线程数
        executor.setMaxPoolSize(20);
        executor.setKeepAliveSeconds(60);
        //配置队列大小
        executor.setQueueCapacity(99999);
        //配置线程池中的线程的名称前缀
        executor.setThreadNamePrefix("async-service-");

        // rejection-policy:当pool已经达到max size的时候,如何处理新任务
        // CALLER_RUNS:不在新线程中执行任务,而是有调用者所在的线程来执行
        executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
        executor.setWaitForTasksToCompleteOnShutdown(true);
        //执行初始化
        executor.initialize();
        return executor;
    }
}

2.然后在需要异步的方法上使用@Async(“线程池名称”) 该方法就可以异步执行了。

	/**
	 * 记录用户登录历史,添加@Async注解异步执行
	 * @param memberLoginHis
	 * @return
	 */
	@Async
	public void save(MemberLoginHis memberLoginHis) {
		memberLoginHis.setCreateTime(new Date());
		memberLoginHis.setType("WEB");
		// 获取IP地址对应的城市
		memberLoginHis.setAddress(AddressUtils.getAddresses(memberLoginHis.getIp()));
		emberLoginHisDao.save(memberLoginHis);
	}

PS:异步线程没生效的原因

1.没有添加注解@EnableAsync注解。//很明显排除
2.异步方法使用注解@Async的返回值只能为void或者Future。 // 也排除
3.没有走Spring的代理类。因为@Transactional和@Async注解的实现都是基于Spring的AOP,而AOP的实现是基于动态代理模式实现的。那么注解失效的原因就很明显了,有可能因为调用方法的是对象本身而不是代理对象,因为没有经过Spring容器

PS解决方法:

1和2没啥好说的,做相应修改就OK,
这里具体说一下第三种情况的解决方法。
1.注解的方法必须是public方法。
2.方法一定要从另一个类中调用,也就是从类的外部调用,类的内部调用是无效的。
3.如果需要从类的内部调用,需要先获取其代理类,下面上代码


BeanFactory factory = WebApplicationContextUtils.getRequiredWebApplicationContext(request.getServletContext());
MemberService memberService = (MemberService) factory.getBean("memberService");

memberService.XXXX();//异步方法
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值