简介
大部分的情况我们的代码的执行都是按照代码的调用顺序来从头执行到尾。打印出线程的名字是http-nio-8080-exec-x 某个线程。在我们执行异步任务的时候需要创建线程池来处理异步任务。
修改启动main
@SpringBootApplication
@EnableAsync
@EnableScheduling
public class StudySpringbootApplication {
public static void main(String[] args) {
SpringApplication.run(StudySpringbootApplication.class, args);
}
}
创建线程池
线程池虽好但也要做好隔离。如果所有的业务都应用一个线程池,当其中的一个业务把线程池占满,就会影响其他的业务正常的运作。我们可以设置几个线程池来定制化为需要的业务。列如: pool1 为异步任务, pool2 为定时任务防止定时任务冲突导致任务的丢弃。
@Configuration
public class PoolConfig {
@Bean(name = "pool1")
public ThreadPoolTaskExecutor taskExecutor() {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
// 设置核心线程数
executor.setCorePoolSize(5);
// 设置最大线程数
executor.setMaxPoolSize(10);
// 设置队列容量
executor.setQueueCapacity(20);
// 设置线程活跃时间(秒)
executor.setKeepAliveSeconds(60);
// 设置默认线程名称
executor.setThreadNamePrefix("wh1-");
// 设置拒绝策略
executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
// 等待所有任务结束后再关闭线程池
executor.setWaitForTasksToCompleteOnShutdown(true);
return executor;
}
@Bean(name = "pool2")
public ThreadPoolTaskExecutor taskExecutor2() {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
// 设置核心线程数
executor.setCorePoolSize(2);
// 设置最大线程数
executor.setMaxPoolSize(4);
// 设置队列容量
executor.setQueueCapacity(20);
// 设置线程活跃时间(秒)
executor.setKeepAliveSeconds(60);
// 设置默认线程名称
executor.setThreadNamePrefix("wh2-");
// 设置拒绝策略
executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
// 等待所有任务结束后再关闭线程池
executor.setWaitForTasksToCompleteOnShutdown(true);
return executor;
}
}
建异步服务
@Service
public class TaskAsyncService {
/**
* 无返回值
* @throws Exception
*/
@Async(value = "pool1")
public void taskOne() throws Exception {
Thread.sleep(4000);
System.out.println("task one " + Thread.currentThread().getName());
}
/**
* 无返回值
* @throws Exception
*/
@Async(value = "pool1")
public void taskTwo() throws Exception {
System.out.println("task two " + Thread.currentThread().getName());
}
/**
* 有返回值回调的异步任务
* @return
* @throws Exception
*/
@Async(value = "pool1")
public Future<String> taskOne2() throws Exception {
Thread.sleep(4000);
System.out.println("task one " + Thread.currentThread().getName());
return new AsyncResult<>("task one done");
}
/**
* 有返回值回调的异步任务
* @return
* @throws Exception
*/
@Async(value = "pool1")
public Future<String> taskTwo2() throws Exception {
System.out.println("task two " + Thread.currentThread().getName());
return new AsyncResult<>("task two done");
}
}
创建action
@GetMapping("/async-test")
public Response taskTest() throws Exception {
/**
* 1.执行http 请求任务的线程是 http-nio-8080-exec ,
* 2.执行 异步任务的线程是自定义线程池中的某个线程
* 3.如果定时任务中的线程默认是开启一个线程,可以通过 @Async 指定线程池中的某个线程
*/
System.out.println("taskTest thread name : " + Thread.currentThread().getName());
//无返回值
//asyncService.taskOne();
//asyncService.taskTwo();
Future<String> future1 = asyncService.taskOne2();
Future<String> future2 = asyncService.taskTwo2();
while (true){
if(future1.isDone() && future2.isDone()){
System.out.println("异步调用完成 : " + future1.get() + future2.get());
break;
}
}
//调用同步函数
this.test1();
return new Response(0, "success");
}
public void test1(){
System.out.println("function test1 : " + Thread.currentThread().getName());
}
定时任务
@Service
public class ScheduleTask {
@Async(value = "pool2")
@Scheduled(fixedRate = 5000)
public void task1(){
/**猜测是维持一个线程 来处理定时任务,如果多个定时任务冲突,这个线程会丢弃掉这个任务*/
System.out.println("schedele task1 :" + Thread.currentThread().getName());
}
}
打印日志
## 方法执行
taskTest thread name : http-nio-8080-exec-1
task two wh1-2
task one wh1-1
异步调用完成 : task one donetask two done
function test1 : http-nio-8080-exec-1
##定时任务
schedele task1 :wh2-2
schedele task1 :wh2-1