1.概念
异步:不阻塞当前线程,而是继续执行下面的流程,并可在线程处理完成后回调通知此线程。
2.使用场景
1)发送短信或注册时,赠送积分。发短信(注册)主线程执行,赠送积分可异步实现。达到快速注册的目的,体验性较好
2)耗时操作,请求接口时,涉及到数据量较大的查询,异步实现查询,线程仅执行接口调用操作。数据查询成功后,返回给主线程
3.实现方式
1)springboot+@Async实现异步
- @EnableAsync注解,可加载启动类或配置类上
@SpringBootApplication
@MapperScan("com.example.demo")
@EnableAsync
public class DemoApplication {
public static void main(String[] args) {
SpringApplication.run(D2Application.class, args);
}
}
- 自定义线程池,默认使用Simpe线程池对象
package org.fiend.async.config;
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;
/**
* 线程池参数配置,多个线程池实现线程池隔离,@Async注解,默认使用系统自定义线程池,可在项目中设置多个线程池,在异步调用的时候,指明需要调用的线程池名称,比如:@Async("taskName")
*/
@EnableAsync
@Configuration
public class TaskPoolConfig {
/**
* 自定义线程池
*/
@Bean("taskExecutor")
public Executor taskExecutor() {
// 返回可用处理器的Java虚拟机的数量 12
int i = Runtime.getRuntime().availableProcessors();
System.out.println("系统最大线程数 : " + i);
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
// 核心线程池大小
executor.setCorePoolSize(16);
// 最大线程数
executor.setMaxPoolSize(20);
// 配置队列容量,默认值为Integer.MAX_VALUE
executor.setQueueCapacity(99999);
// 活跃时间
executor.setKeepAliveSeconds(60);
// 线程名字前缀
executor.setThreadNamePrefix("asyncServiceExecutor -");
// 设置此执行程序应该在关闭时阻止的最大秒数,以便在容器的其余部分继续关闭之前等待剩余的任务完成他们的执行
executor.setAwaitTerminationSeconds(60);
// 等待所有的任务结束后再关闭线程池
executor.setWaitForTasksToCompleteOnShutdown(true);
return executor;
}
}
- @Async注解,可配置方法或类上;类上代表整个类的所有方法均为异步,方法上仅针对该方法
@Service
@Slf4j
public class TestService {
@Async
public void sync() {
log.info("异步方法-" + Thread.currentThread().getName() + ",start:" + LocalDateTime.now());
try {
Thread.sleep(5000L);
} catch (InterruptedException e) {
e.printStackTrace();
}
log.info("异步方法-" + Thread.currentThread().getName() + ",end:" + LocalDateTime.now());
}
}
2)CompletableFuture实现异步
方法无需添加注解,如下图亦可看出,CompletableFuture创建的两个子线程并不会影响主线程执行,两个子线程之间也不会相互影响,如图1。**注意:**调用CompletableFuture的get等方法时,会造成线程阻塞,如图2。
public String test2() throws Exception {
CompletableFuture<String> cf = CompletableFuture.supplyAsync(()->{
try {
Thread.sleep(10000L);
System.out.println("子线程:"+Thread.currentThread().getName());
System.out.println("子线程:"+ LocalDateTime.now());
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
return "1";
});
CompletableFuture<String> cf2 = CompletableFuture.supplyAsync(()->{
try {
Thread.sleep(5000L);
System.out.println("子线程2:"+Thread.currentThread().getName());
System.out.println("子线程2:"+ LocalDateTime.now());
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
return "1";
});
System.out.println("主线程:"+Thread.currentThread().getName());
System.out.println("主线程:"+ LocalDateTime.now());
return "";
}




1939

被折叠的 条评论
为什么被折叠?



