本文介绍: 在异步任务执行的时候,我们知道其背后都有一个线程池来执行任务,但是为了控制异步任务并发影响应用的正常运作,我们需要对线程池做好相关的配置,以防资源过度使用。这个时候我们考虑将线程池进行隔离了。

异步任务执行的时候,我们知道其背后都有一个线程池来执行任务,但是为了控制异步任务并发影响应用的正常运作,我们需要对线程池做好相关的配置,以防资源过度使用。这个时候我们就考虑将线程池进行隔离了。

那么我们为啥要隔离@Async异步任务的线程池?

下面看一个demo

demo

  1. 创建自定义的线程池:首先,你可以创建一个自定义的线程池,用于处理@Async注解标记的异步任务。可以使用ThreadPoolTaskExecutor类来创建线程池。

    @Configuration
    @EnableAsync
    public class AsyncConfig implements AsyncConfigurer {
    
        @Bean(name = "asyncTaskExecutor")
        public Executor asyncTaskExecutor() {
            ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
            // 配置线程池属性
            executor.setCorePoolSize(10);
            executor.setMaxPoolSize(20);
            executor.setQueueCapacity(100);
            executor.setThreadNamePrefix("AsyncTask-");
            executor.initialize();
            return executor;
        }
    
        @Override
        public Executor getAsyncExecutor() {
            return asyncTaskExecutor();
        }
    }
    

    在上述示例中,我们创建了一个名为asyncTaskExecutor的线程池,并配置核心线程数、最大线程数、队列容量等属性

  2. 在异步任务方法指定线程池:接下来,你可以在需要异步执行的方法上使用@Async注解,并通过value属性指定要使用的线程池。

    @Service
    public class MyService {
    
       @Async("asyncTaskExecutor")
       public void asyncMethod() {
           // 异步任务的具体逻辑
       }
    }
    

    在上述示例中,我们使用@Async("asyncTaskExecutor")注解将asyncMethod()方法标记为异步任务,并指定了使用名为asyncTaskExecutor的线程池。

实际案例

记得在启动类中添加@EnableAsync注解呀

我们来初始化多个线程池:

@EnableAsync
@Configuration
public class TaskPoolConfig {

    @Bean
    public Executor taskExecutor1() {
        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
        executor.setCorePoolSize(2);
        executor.setMaxPoolSize(2);
        executor.setQueueCapacity(10);
        executor.setKeepAliveSeconds(60);
        //使用线程名前缀,可以用来观察顺序
        executor.setThreadNamePrefix("executor-1-");
        executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
        return executor;
    }

    @Bean
    public Executor taskExecutor2() {
        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
        executor.setCorePoolSize(2);
        executor.setMaxPoolSize(2);
        executor.setQueueCapacity(10);
        executor.setKeepAliveSeconds(60);
        executor.setThreadNamePrefix("executor-2-");
        executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
        return executor;
    }
}

接下来创建一个异步任务,然后指定要使用线程池名字。

@Slf4j
@Component
public class AsyncTasks {

    public static Random random = new Random();

    @Async("taskExecutor1")
    public CompletableFuture<String&gt; doTaskOne(String taskNo) throws Exception {
        log.info("开始任务:{}", taskNo);
        long start = System.currentTimeMillis();
        Thread.sleep(random.nextInt(10000));
        long end = System.currentTimeMillis();
        log.info("完成任务:{},耗时:{} 毫秒", taskNo, end - start);
        return CompletableFuture.completedFuture("任务完成");
    }

    @Async("taskExecutor2")
    public CompletableFuture<String> doTaskTwo(String taskNo) throws Exception {
        log.info("开始任务:{}", taskNo);
        long start = System.currentTimeMillis();
        Thread.sleep(random.nextInt(10000));
        long end = System.currentTimeMillis();
        log.info("完成任务:{},耗时:{} 毫秒", taskNo, end - start);
        return CompletableFuture.completedFuture("任务完成");
    }

}

创建一个测试类:

@Slf4j
@SpringBootTest
public class ApplicationTests {

    @Autowired
    private AsyncTasks asyncTasks;

    @Test
    public void test() throws Exception {
        long start = System.currentTimeMillis();

        // 线程池1
        CompletableFuture<String> task1 = asyncTasks.doTaskOne("1");
        CompletableFuture<String> task2 = asyncTasks.doTaskOne("2");
        CompletableFuture<String> task3 = asyncTasks.doTaskOne("3");

        // 线程池2
        CompletableFuture<String> task4 = asyncTasks.doTaskTwo("4");
        CompletableFuture<String> task5 = asyncTasks.doTaskTwo("5");
        CompletableFuture<String> task6 = asyncTasks.doTaskTwo("6");

        // 一起执行
        CompletableFuture.allOf(task1, task2, task3, task4, task5, task6).join();

        long end = System.currentTimeMillis();

        log.info("任务全部完成,总耗时:" + (end - start) + "毫秒");
    }

}

在上面的单元测试中,一共启动了6个异步任务,前三个用的是线程池1,后三个用的是线程池2。

先不执行,根据设置核心线程2和最大线程数2,我们来猜猜线程的执行顺序

  • 线程池1的三个任务,task1和task2会先获得执行线程,然后task3因为没有可分配线程进入缓冲队列

  • 线程池2的三个任务,task4和task5会先获得执行线程,然后task6因为没有可分配线程进入缓冲队列

  • 任务task3会在task1或task2完成之后,开始执行

  • 任务task6会在task4或task5完成之后,开始执行

执行结果
在这里插入图片描述
通过以上步骤,你可以实现@Async异步任务的线程池进行隔离。这样可以根据需要创建多个线程池,并为不同的异步任务指定不同的线程池,以实现任务之间的隔离和资源控制。通过隔离@Async异步任务的线程池,可以实现系统资源的控制、性能的优化业务逻辑的隔离。这样可以提高系统的稳定性、可伸缩性和灵活性,更好地满足不同业务场景下的需求

原文地址:https://blog.csdn.net/qq_45922256/article/details/134653466

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任

如若转载,请注明出处:http://www.7code.cn/show_14453.html

如若内容造成侵权/违法违规/事实不符,请联系代码007邮箱suwngjj01@126.com进行投诉反馈,一经查实,立即删除

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注