在SpringBoot项目中,
如有这样的场景:当用户点击了博客,
此时,后台既需要返回这个博客的内容,同时也需要修改该博客的阅读记录数。
博客内容是需要立即返回的,是主线程,而修改阅读记录数则可以放入分线程中执行,这样,会提交效率。因为若是同步执行,则这两个步骤需要全部执行完才返回页面信息。
在SpringBoot中自带了异步编程函数ThreadPoolTaskExecutor
所以无须添加别的依赖。直接用即可
注意:这里介绍两种方式。但这两种方式不兼容,如果都使用项目会报错不能启动
方式1 默认的方式
package com.imut.controller;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.concurrent.CompletableFuture;
/**
* @author djs
* @create 2022-11-28 10:40
*/
@RestController
public class UserController {
//直接使用即可
@Autowired
private ThreadPoolTaskExecutor executor;
//传统的同步代码方式
@GetMapping("/user")
public String do1(){
long start = System.currentTimeMillis();
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
long end = System.currentTimeMillis();
return "执行所花费的时间:"+(end-start); //5003
}
@GetMapping("/user2")
public String do2(){
long start = System.currentTimeMillis();
// 异步执行
CompletableFuture<Void> completableFuture = CompletableFuture.runAsync(() ->{
// 这里写具体的代码
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("执行具体的任务1....");
},executor);
// 异步执行
CompletableFuture<Void> completableFuture2 = CompletableFuture.runAsync(() ->{
// 这里写具体的代码
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("执行具体的任务2....");
},executor);
// 这里是主程序代码
long end = System.currentTimeMillis();
return "执行所花费的时间:"+(end-start); //0
}
}
方式2 添加配置类
1。配置类ThreadPoolConfig.java
package com.imut.config;
/**
* @author djs
* @create 2022-11-28 14:45
*/
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;
@Configuration
@EnableAsync
public class ThreadPoolConfig {
@Bean("taskExecutor")
public Executor asyncServiceExecutor() {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
// 设置核心线程数
executor.setCorePoolSize(5);
// 设置最大线程数
executor.setMaxPoolSize(20);
//配置队列大小
executor.setQueueCapacity(Integer.MAX_VALUE);
// 设置线程活跃时间(秒)
executor.setKeepAliveSeconds(60);
// 设置默认线程名称
executor.setThreadNamePrefix("码神之路博客项目");
// 等待所有任务结束后再关闭线程池
executor.setWaitForTasksToCompleteOnShutdown(true);
//执行初始化
executor.initialize();
return executor;
}
}
2。把异步的代码写到Service层
ThreadStuService.java
package com.imut.service;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Component;
/**
* @author djs
* @create 2022-11-28 14:47
*/
@Component
public class ThreadStuService {
@Async("taskExecutor") // 这里写线程池配置类的Bean名称
public void dosome(){
try {
Thread.sleep(3000);
/**
* 这里可以写一些需要修改的操作
* 如博客在打开的时,既需要展示博客的内容
* 也需要修改博客的阅读记录数
*
* 当用户点击博客后,应该立即展示内容
* 而修改博客的阅读记录数可放到异步线程池中执行。不影响效率
*/
System.out.println("异步代码执行....");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
控制器层直接引用用Service层即可
StuController.java
package com.imut.controller;
import com.imut.service.ThreadStuService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
/**
* @author djs
* @create 2022-11-28 14:46
*/
@RestController
public class StuController {
// 把需要异步执行的程序放到Service层中
@Autowired
private ThreadStuService threadStuService;
@GetMapping("/stu")
public String dosome(){
try {
Thread.sleep(2000);
System.out.println("执行主线程");
} catch (InterruptedException e) {
e.printStackTrace();
}
// 执行分线程
threadStuService.dosome();
return "成功";
}
}