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 "短信發送完成";
	}
}

  


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM