Spring Boot实现异步调用(多线程)

Spring Boot实现异步调用(多线程)

制作人:全心全意

Spring Boot实现异步调用(多线程)

  启动加上@EnableAsync,需要执行的异步方法上加上@Async
  @Async实际上就是多线程封装的
  使用场景例如,发送短信验证码
  异步线程执行方法有可能会非常消耗CPU资源,所以大的项目建议使用MQ异步实现

  失效问题:如果异步注解写成当前自己类,有可能aop会失效,无法拦截注解,最终导致异步失效,需要经过代理类调用接口,所以需要将异步的代码单独抽取成一个类调用接口。

 

多线程使用示例(不使用注解),不建议使用

package com.zq.controller;

import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import lombok.extern.slf4j.Slf4j;

@RestController
@Slf4j
public class Myxiancheng {

	@RequestMapping("/d1xiancheng")
	public String d1xiancheng() {
		log.info("======1=======");

		// 发送短信
		// 单线程
		// sms();
		// 多线程
		new Thread(new Runnable() {

			@Override
			public void run() {
				sms();
			}
		}).start();

		log.info("======4=======");
		return "我是返回结果";
	}

	public String sms() {
		log.info("======2=======");
		try {
			log.info("正在发送短信======");
			Thread.sleep(3000);
		} catch (Exception e) {

		}
		log.info("======3=======");
		return "短信发送完成";
	}
}

  

 

多线程使用示例(使用注解)

失效问题:如果异步注解写成当前自己类,有可能aop会失效,无法拦截注解,最终导致异步失效,需要经过代理类调用接口,所以需要将异步的代码单独抽取成一个类调用接口(不要在一个包中)。异步方法和controller不要在一个包中

线程方法类

package com.zq.async;

import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Component;

import lombok.extern.slf4j.Slf4j;

@Component
@Slf4j
public class MyAsync {
	@Async
	public String sms() {
		log.info("======2=======");
		try {
			log.info("正在发送短信======");
			Thread.sleep(3000);
		} catch (Exception e) {

		}
		log.info("======3=======");
		return "短信发送完成";
	}
}

  

调用controller类

package com.zq.controller;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import com.zq.async.MyAsync;

import lombok.extern.slf4j.Slf4j;

@RestController
@Slf4j
public class Myxiancheng {

	@Autowired
	private MyAsync myAsync;

	@RequestMapping("/d1xiancheng")
	public String d1xiancheng() {
		log.info("======1=======");

		// 发送短信
		myAsync.sms();

		log.info("======4=======");
		return "我是返回结果";
	}

}

  

启动类

package com.zq;

import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.scheduling.annotation.EnableAsync;

@SpringBootApplication
@EnableAsync // 开启异步注解
@MapperScan("com.zq.mapper") // 默认不会扫描mapper,需要此注解指定
public class App {
	public static void main(String[] args) {
		SpringApplication.run(App.class, args);
	}

}

  

 

整合线程池

不建议频繁创建线程,频繁的创建线程效率非常低,所以使用线程池

创建线程池配置类

package com.zq.config;

import java.util.concurrent.ThreadPoolExecutor;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.task.TaskExecutor;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;

@Configuration
@EnableAsync
public class ThreadPoolConfig {

	/**
	 * 每秒需要多少个线程处理
	 * tasks/(1/taskcost)
	 */
	private int corePoolSize = 3;
	
	
	/**
	 * 线程池维护线程的最大数量
	 * (max(tasks)- queueCapacity)/(1/taskcost)
	 */
	private int maxPoolSize = 3;
	
	/**
	 * 缓存队列
	 * (coreSizePool/taskcost)*responsetime
	 */
	private int queueCapacity = 10;
	
	/**
	 * 允许的空闲时间
	 * 默认为60
	 */
	private int keepAlive = 100;
	
	@Bean
	public TaskExecutor taskExecutor() {
		ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
		//设置核心线程数
		executor.setCorePoolSize(corePoolSize);
		//设置最大线程数
		executor.setMaxPoolSize(maxPoolSize);
		//设置队列容量
		executor.setQueueCapacity(queueCapacity);
		//设置允许的空闲时间(秒)
		//executor.setKeepAliveSeconds(keepAlive);
		//设置默认的线程名称
		executor.setThreadNamePrefix("thread-");
		//设置拒绝策略rejection-policy:当pool已经达到max size的时候,如何处理新任务
		executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
		executor.setWaitForTasksToCompleteOnShutdown(true);
		return executor;
	}
}

  

使用线程池

package com.zq.async;

import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Component;

import lombok.extern.slf4j.Slf4j;

@Component
@Slf4j
public class MyAsync {
	@Async("taskExecutor")	//使用taskExecutor线程池
	public String sms() {
		log.info("======2=======");
		try {
			log.info("正在发送短信======");
			Thread.sleep(3000);
		} catch (Exception e) {

		}
		log.info("======3=======");
		return "短信发送完成";
	}
}

  

posted @ 2020-12-22 23:01  全心全意_运维  阅读(8928)  评论(0编辑  收藏  举报