@Async 结合CompleteableFuture

本文介绍了如何在Springboot中使用Async和CompletableFuture进行异步编程,避免了将解锁逻辑与异步任务绑定的问题,并讨论了如何在异步任务中携带调用者上下文,以及如何通过自定义任务装饰类来实现这一功能。
摘要由CSDN通过智能技术生成

@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();
            }
        };
    }
}

而指定的线程池里面,用我们的任务装饰类,自然就可以包裹上下文了,这样我们异步任务也自带上下文了。

LinkedBlockingDeque是Java中的一个双向队列,支持并发操作。@Async是Spring框架中的一个注解,用于异步执行方法。结合使用LinkedBlockingDeque和@Async可以实现一个高效的异步队列。 首先,需要在Spring配置文件中开启@EnableAsync注解,以启用异步执行方法的功能。然后,定义一个包含@Async注解的方法,该方法将会被异步执行。在方法中,将需要异步执行的任务加入到LinkedBlockingDeque中。 下面是一个示例代码: ```java @Configuration @EnableAsync public class AppConfig { @Bean public Executor asyncExecutor() { ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor(); executor.setCorePoolSize(5); executor.setMaxPoolSize(10); executor.setQueueCapacity(25); return executor; } } @Service public class MyService { private LinkedBlockingDeque<Task> taskQueue = new LinkedBlockingDeque<>(); @Async public void processTasks() { while (true) { try { Task task = taskQueue.take(); // 处理任务 } catch (InterruptedException e) { Thread.currentThread().interrupt(); break; } } } public void addTask(Task task) { taskQueue.offer(task); } } ``` 在上面的代码中,AppConfig类定义了一个线程池,用于异步执行方法。MyService类定义了一个LinkedBlockingDeque对象,用于存储任务。addTask方法用于将任务加入到队列中。processTasks方法使用@Async注解,表示该方法将会异步执行。在该方法中,使用take方法从队列中获取任务,并处理任务。 使用LinkedBlockingDeque结合@Async可以实现高效的异步队列,可以应用于各种场景,例如消息队列、任务队列等。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值