1、配置BeanConfig,线程池的基础配置
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;
/**
* @author yhg:
* @version 创建时间:2021年8月9日 上午8:54:33
* 类说明
*/
@Configuration
@EnableAsync
public class BeanConfig {
@Bean
public TaskExecutor taskExecutor() {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
// 设置核心线程数
// 线程池在完成初始化之后,默认情况下,线程池中不会有任何线程,线程池会等有任务来的时候再去创建线程。
// 核心线程创建出来后即使超出了线程保持的存活时间配置也不会销毁,核心线程只要创建就永驻了,就等着新任务进来进行处理。
executor.setCorePoolSize(5);
// 设置最大线程数
// 核心线程忙不过来且任务存储队列满了的情况下,还有新任务进来的话就会继续开辟线程,但是也不是任意的开辟线程数量,线程数(包含核心线程)
// 达到maximumPoolSize后就不会产生新线程了,就会执行拒绝策略。
executor.setMaxPoolSize(10);
// 设置队列容量
// 核心线程数满了后还有任务继续提交到线程池的话,就先进入workQueue。
executor.setQueueCapacity(20);
// 设置线程活跃时间(秒)
// 如果线程池当前的线程数多于corePoolSize,那么如果多余的线程空闲时间超过keepAliveTime,那么这些多余的线程(超出核心线程数的那些线程)就会被回收。
executor.setKeepAliveSeconds(60);
// 设置默认线程名称
executor.setThreadNamePrefix("MyThread-");
// 设置拒绝策略
executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
// 等待所有任务结束后再关闭线程池
executor.setWaitForTasksToCompleteOnShutdown(true);
return executor;
}
}
2、创建MainController控制类来操作线程以及有返回值的线程实现
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import org.slf4j.LoggerFactory;
import org.springframework.scheduling.annotation.Async;
import org.springframework.scheduling.annotation.AsyncResult;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
/**
* @author yhg:
* @version 创建时间:2021年8月8日 下午3:06:52
* 类说明
*/
@RestController
public class MainController {
@Async
@RequestMapping("/Threadtest1")
public void sayHello1(String name) {
while(true) {
LoggerFactory.getLogger(MainController.class).info(Thread.currentThread().getName() + ":Hello World1111111111!");
// TODO: handle exception
try {
Thread.sleep(1000);
} catch (InterruptedException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
}
}
@Async
@RequestMapping("/Threadtest2")
public void sayHello2(String name) {
while(true) {
LoggerFactory.getLogger(MainController.class).info(Thread.currentThread().getName() + ":Hello World2222222222!");
// TODO: handle exception
try {
Thread.sleep(1000);
} catch (InterruptedException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
}
}
//有回调异步 Future<String>,通过Future.get()方法调用返回值
@Async
@RequestMapping("/Threadtest3")
public Future<String> sayHello3() throws Exception {
LoggerFactory.getLogger(MainController.class).info(Thread.currentThread().getName() + ":任务一!");
// TODO: handle exception
String a="get CallBackResult";
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
}
//return new AsyncResult<>(String.format("这个是第1个异步调用的证书"));
return new AsyncResult<String>(String.format(a));
}
@RequestMapping("/Threadtest4")
public String getCallBack() {
try {
Future<String> fu = sayHello3();
//获取返回值
if(fu.isDone()) {
System.out.println(fu.get());
return fu.get();
}
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return "a";
}
}
我这里写了4个接口用来实现操作,Threadtest1与Threadtest2来证明线程池是否以及启用,Threadtest3实现有返回值的线程,Threadtest4调用Threadtest3查看结果。
直接运行,利用postman进行接口调用,查看控制台。
此时可以看见,Threadtest1已经正常运行,并且线程名称遵循了线程池中的配置
executor.setThreadNamePrefix("MyThread-");同理我们调用Threadtest2,继续查看控制台,看运行情况。
可以看见,Threadtest2正常运行。
在Threadtest3接口中,我们想要实现有返回值的线程,这里使用Future进行回调,返回一个String字符串,这里我们直接调用Threadtest4查看结果。
可以看出,控制台输出了返回值get CallBackResult,至此整个功能完成。