SpringBoot实现多线程

多线程方式一:实现AsyncConfigurer 接口

配置类实现接口AsyncConfigurer,返回一个ThreadPoolTaskExecutor 线程池对象。

@Configuration
@EnableAsync
public class AsyncConfig implements AsyncConfigurer {

    // ThredPoolTaskExcutor的处理流程
    // 当池子大小小于corePoolSize,就新建线程,并处理请求
    // 当池子大小等于corePoolSize,把请求放入workQueue中,池子里的空闲线程就去workQueue中取任务并处理
    // 当workQueue放不下任务时,就新建线程入池,并处理请求,如果池子大小撑到了maximumPoolSize,就用RejectedExecutionHandler来做拒绝处理
    // 当池子的线程数大于corePoolSize时,多余的线程会等待keepAliveTime长时间,如果无请求可处理就自行销毁

    @Override
    @Bean
    public Executor getAsyncExecutor() {
        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
        // 核心线程数:线程池创建的时候初始化的线程数
        executor.setCorePoolSize(10);
        // 最大线程数:线程池最大的线程数,只有缓冲队列满了之后才会申请超过核心线程数的线程
        executor.setMaxPoolSize(100);
        // 缓冲队列:用来缓冲执行任务的队列
        executor.setQueueCapacity(50);
        // 线程池关闭:等待所有任务都完成再关闭
        executor.setWaitForTasksToCompleteOnShutdown(true);
        // 等待时间:等待5秒后强制停止
        executor.setAwaitTerminationSeconds(5);
        // 允许空闲时间:超过核心线程之外的线程到达60秒后会被销毁
        executor.setKeepAliveSeconds(60);
        // 线程名称前缀
        executor.setThreadNamePrefix("learn-Async-");
        // 初始化线程
        executor.initialize();
        return executor;
    }

    @Override
    public AsyncUncaughtExceptionHandler getAsyncUncaughtExceptionHandler() {
        return null;
    }
}

通过@Async注解表明该方法是异步方法,如果注解在类上,那表明这个类里面的所有方法都是异步的。 

@Service
public class AsyncService {
    @Async  // 表明该方法是异步方法。如果注解在类上,那表明类里面的所有方法都是异步
    public void executeAsyncTask(int i) {
        System.out.println("线程" + Thread.currentThread().getName() + " 执行异步任务:" + i);
    }
}

多线程方式二:配置 java.util.concurrent.TaskExecutor

新增一个配置类,默认情况下使用 SimpleAsyncTaskExecutor

@Configuration
@EnableAsync //启用异步任务
public class ThreadConfig {
    @Bean("asyncServiceExecutor")
    public ThreadPoolTaskExecutor executor(){
        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
      	//配置核心线程数
        executor.setCorePoolSize(15);
      	//配置最大线程数
        executor.setMaxPoolSize(30);
      	//配置队列大小
        executor.setQueueCapacity(1000);
      	//线程的名称前缀
        executor.setThreadNamePrefix("Executor-");
      	//线程活跃时间(秒)
        //executor.setKeepAliveSeconds(60);
      	//等待所有任务结束后再关闭线程池
        executor.setWaitForTasksToCompleteOnShutdown(true);
      	//设置拒绝策略
        //executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
      	//执行初始化
        executor.initialize();
        return executor;
    }
}

使用线程池:可以使用@Async注解或者直接调用TaskExecutor的submit或者execute方法提交任务。

//-----------------------接口类--------------------------
public interface UserService{
    /**
  	 * 执行异步任务
  	 */
    void writeText();
}
//-----------------------接口实现类----------------------
@Service
public class UserServiceImpl implement UserService{
    private static Logger logger = LogManager.getLogger(AsyncServiceImpl.class.getName());

    @Async("asyncServiceExecutor")
    @Over
    public void writeTxt(String fileName){
        logger.info("线程-" + Thread.currentThread().getId() + "在执行写入");
        try {
            File file = new File(fileName);
            List<String> lines = FileUtils.readLines(file);
            File copyFile = new File(fileName + "_copy.txt");
            lines.stream().forEach(string->{
                try {
                    FileUtils.writeStringToFile(copyFile,string,"utf8",true);
                    FileUtils.writeStringToFile(copyFile,"\r\n","utf8",true);
                } catch (IOException e) {
                    logger.info(e.getMessage());
                }
            });
        }catch (Exception e) {
            logger.info(e.getMessage());
        }
    }
}
//-----------------------测试----------------------------
@RunWith(SpringRunner.class)
@SpringBootTest
public class BootApplicationTests {
    @Autowired
    private AsyncService asyncService;

    @Test
    public void write() {
        File file = new File("F://ac_code_1//test.txt");
        try {
            FileUtils.writeStringToFile(file, "ceshi", "utf8");
            FileUtils.writeStringToFile(file, "\r\n", "utf8");
            FileUtils.writeStringToFile(file, "ceshi2", "utf8");
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

@Async原理

本质上Async注解的实现依赖于动态代理,代理过程中将任务提交给线程池,存在以下流程:

如上图所示,Spring为使用Async注解Bean对象生产一个动态代理对象,当Async注解的方法被调用时,会进入代理流程,选择线程池、封装调用逻辑并提交给线程池执行,返回执行结果。

注意:未被@Async注解的方法则不会执行上述流程(static方法也不会)

由于异步的本质是基于代理实现,所以同一个类中的方法调用会导致被调用方的异步作用失效,该场景与Spring的事务失效原因相同。

注解@Async失效的情况

  • 注解@Async的方法不是public方法
  • 注解@Async的返回值只能为void或Future
  • 注解@Async方法使用static修饰也会失效
  • spring无法扫描到异步类,没加注解@Async或@EnableAsync注解
  • 调用方与被调用方不能在同一个类(因为没走代理)
  • 类中需要使用@Autowired或@Resource等注解自动注入,不能自己手动new对象
  • 在Async方法上标注@Transactional是没用的,但在Async方法调用的方法上标注@Transcational是有效的

 

posted @ 2023-02-12 10:36  残城碎梦  阅读(985)  评论(0编辑  收藏  举报