@Async 结合CompleteableFuture
需求背景,我们经常有那种加分布式锁的时候,在发起异步任务前,我们会尝试加锁,如果加锁成功,说明没人执行,那我们就开始执行,然后发起了一个异步任务,但是这个时候,就会有个尴尬的问题,解锁逻辑要耦合到异步任务逻辑里去了,但是明显不太符合逻辑,这个只是个执行任务,为什么会嵌入一个解锁的逻辑。所以自然就想到,java中有没有注册回调函数的逻辑,当我线程执行完成后,执行对应的操作。
这个时候,自然就想到联排任务 CompletableFuture 来实现异步编程。
那么怎么使用呢,如果是自定义的线程池执行,那自然只要执行返回future就好,那如果是@Async来弄的,支持future吗,自然也是支持的。
Springboot Async异步扩展使用 结合 CompletableFuture_asynccompletablefuture-CSDN博客
这里啰嗦一句,我们经常要发起异步任务的时候,需要带上调用者的上下文,比如调用者。而常见的写法的话,主要是这么几种,一种是直接方法参数传入,然后重设上下文就好。但这个缺点就是,每个方法参数都要带入,写的很烦。还有的话,就是任务装饰类,因为我们任务执行基本都是有线程池的,无非是自定义的线程池还是默认,基本都是自定义的,而申请执行,有两种实现,一种就是工具类,一种就是@Aysnc这种,@Aysnc的默认线程池,我们自然可以修改。或者@Aynsc(“指定我们的线程池”)。
@Configuration
@Slf4j
public class AsyncConfiguration {
@Bean("myAsyncExecutor")
public ThreadPoolTaskExecutor executor() {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
int corePoolSize = 10;
executor.setCorePoolSize(corePoolSize);
int maxPoolSize = 50;
executor.setMaxPoolSize(maxPoolSize);
int queueCapacity = 2000;
executor.setQueueCapacity(queueCapacity);
executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
String threadNamePrefix = "myExecutor-";
executor.setThreadNamePrefix(threadNamePrefix);
executor.setWaitForTasksToCompleteOnShutdown(true);
// 使用自定义的跨线程的请求级别线程工厂类19
int awaitTerminationSeconds = 5;
executor.setAwaitTerminationSeconds(awaitTerminationSeconds);
executor.setTaskDecorator(new MyTaskDecorator());
executor.initialize();
return executor;
}
}
public class MyTaskDecorator implements TaskDecorator {
@Override
public Runnable decorate(Runnable runnable) {
MemberInfo memberInfo = MemberHolder.getMemberInfo();
Long loggerSn = CommonContextHolder.getLoggerSn();
return ()->{
try {
CommonContextHolder.setLoggerSn(loggerSn);
MemberHolder.bindMember(memberInfo);
runnable.run();
}finally {
MemberHolder.unbindMember();
CommonContextHolder.removeLoggerSn();
}
};
}
}
而指定的线程池里面,用我们的任务装饰类,自然就可以包裹上下文了,这样我们异步任务也自带上下文了。