spring异步线程任务Async,自定义配置线程池,Java

本文介绍Spring框架中如何使用@Async注解执行异步任务,并演示了自定义线程池配置的方法,包括单一线程池的配置及多个线程池的配置与使用。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

spring异步线程任务Async,自定义配置线程池,Java

(一)spring里面,可以通过简洁的@Async使用默认的线程池跑多线程任务。

package zhangphil.demo;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.scheduling.annotation.EnableAsync;

@SpringBootApplication
@EnableAsync
public class TestApplication {
    public static void main(String[] args) {
        ConfigurableApplicationContext context=SpringApplication.run(TestApplication.class, args);
    }
}

主Application,需要配置注解 @EnableAsync 启动异步线程任务。

package zhangphil.demo;

import lombok.extern.slf4j.Slf4j;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Component;

@Slf4j
@Component
public class MyTask {
    private int a = 0;
    private int b = 0;
    private int c = 0;

    @Async
    public void task1() {
        log.info("t-a ...");
        try {
            Thread.sleep(5000);
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }
        log.info("t-a-{}", a++);
    }

    @Async
    public void task2() {
        log.info("t-b ...");
        try {
            Thread.sleep(5000);
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }
        log.info("t-b-{}", b++);
    }

    @Async
    public void task3() {
        log.info("t-c ...");
        try {
            Thread.sleep(5000);
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }
        log.info("t-c-{}", c++);
    }
}

上面就是异步线程任务的主要模块。

下面做一个Controller,没别的功能,只为在浏览器输入localhost:8080/start启动task1(),task2(),task()3:

package zhangphil.demo;

import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;

@RestController
@Slf4j
public class MyController {
    @Autowired
    private MyTask myTask;

    @RequestMapping(value = "/start", method = RequestMethod.GET)
    private String start() {
        myTask.task1();
        myTask.task2();
        myTask.task3();
        log.info("start ok");
        return "OK";
    }
}

启动后,在浏览器访问localhost:8080/start后,后台输出:

 spring默认的为多线程任务装载了线程名为 task-1,task-2,task-3 启动它们。以上代码我们并没有主动创建线程池,而是spring默默的用框架包装好的ThreadPoolTaskExecutor为我们的代码启动了多线程。

(二)自定义配置Async的线程池。

以上是spring原生的多线程异步任务框架,我们没有添加任何配置参数,只是简单的调用。如果要自定义更细颗粒度的使用和理解线程池任务,可以通过配置@Configuration配置AsyncConfigurer

实现对spring框架默认的ThreadPoolTaskExecutor二次定制化配置,配置代码:

package zhangphil.demo;

import org.springframework.aop.interceptor.AsyncUncaughtExceptionHandler;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.annotation.AsyncConfigurer;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;

import java.util.concurrent.Executor;
import java.util.concurrent.ThreadPoolExecutor;

@Configuration
public class MyAsyncConfigurer implements AsyncConfigurer {

    @Override
    public Executor getAsyncExecutor() {
        return executor();
    }

    @Bean("myTaskExecutor")
    public ThreadPoolTaskExecutor executor() {
        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();

        int corePoolSize = 10;
        executor.setCorePoolSize(corePoolSize);

        int maxPoolSize = 50;
        executor.setMaxPoolSize(maxPoolSize);

        int queueCapacity = 10;
        executor.setQueueCapacity(queueCapacity);

        executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());

        String threadNamePrefix = "my-task@";
        executor.setThreadNamePrefix(threadNamePrefix);

        //executor.setAwaitTerminationMillis(100*1000);
        //executor.setWaitForTasksToCompleteOnShutdown(true);
        //executor.setAllowCoreThreadTimeOut(true);

        executor.setKeepAliveSeconds(60 * 1000);

        executor.initialize();

        return executor;
    }

    @Override
    public AsyncUncaughtExceptionHandler getAsyncUncaughtExceptionHandler() {
        return AsyncConfigurer.super.getAsyncUncaughtExceptionHandler();
    }
}

MyTask.java不做任何修改,运行后输出:

 可以看到,此时的线程任务名称已经变为我们自定义的my-task@ 开头。

(三)配置多个线程池。

有些项目中的线程池可能不止一个,而是三个甚至更多,那就不太适合通过(二)中的技术路线实现了,而需要更一般、更通用的方法实现。

package zhangphil.demo;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;

import java.util.concurrent.ThreadPoolExecutor;

@Configuration
public class MyTaskExecutor {

    @Bean("executorA")
    public ThreadPoolTaskExecutor executorA() {
        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();

        int corePoolSize = 10;
        executor.setCorePoolSize(corePoolSize);

        int maxPoolSize = 50;
        executor.setMaxPoolSize(maxPoolSize);

        int queueCapacity = 10;
        executor.setQueueCapacity(queueCapacity);

        executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());

        String threadNamePrefix = "task@A-";
        executor.setThreadNamePrefix(threadNamePrefix);

        //executor.setAwaitTerminationMillis(100*1000);
        //executor.setWaitForTasksToCompleteOnShutdown(true);
        //executor.setAllowCoreThreadTimeOut(true);

        executor.setKeepAliveSeconds(60 * 1000);

        executor.initialize();

        return executor;
    }

    @Bean("executorB")
    public ThreadPoolTaskExecutor executorB() {
        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();

        int corePoolSize = 10;
        executor.setCorePoolSize(corePoolSize);

        int maxPoolSize = 50;
        executor.setMaxPoolSize(maxPoolSize);

        int queueCapacity = 10;
        executor.setQueueCapacity(queueCapacity);

        executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());

        String threadNamePrefix = "task@B-";
        executor.setThreadNamePrefix(threadNamePrefix);

        //executor.setAwaitTerminationMillis(100*1000);
        //executor.setWaitForTasksToCompleteOnShutdown(true);
        //executor.setAllowCoreThreadTimeOut(true);

        executor.setKeepAliveSeconds(60 * 1000);

        executor.initialize();

        return executor;
    }
}

上面代码通过@Configuration定义了不同于spring框架默认的那个多线程池子,这两个单独自定义的线程池名分别以task@A-和task@B-开头。多线程池实现了,对应的使用这两个线程池的任务代码模块也需要调整:

package zhangphil.demo;

import lombok.extern.slf4j.Slf4j;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Component;

@Slf4j
@Component
public class MyTask {
    private int a = 0;
    private int b = 0;
    private int c = 0;

    @Async("executorA")
    public void task1() {
        log.info("t-a ...");
        try {
            Thread.sleep(5000);
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }
        log.info("t-a-{}", a++);
    }

    @Async
    public void task2() {
        log.info("t-b ...");
        try {
            Thread.sleep(5000);
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }
        log.info("t-b-{}", b++);
    }

    @Async("executorB")
    public void task3() {
        log.info("t-c ...");
        try {
            Thread.sleep(5000);
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }
        log.info("t-c-{}", c++);
    }
}

注意task2(),特意没有给@Async加上寻址名字。看看后台运行输出:

 从输出可以看到,由于在task1()和task3()指定了@Async()需要启用的线程池executorA和executorB,所以task1()和task3()的多线程任务分别被executorA和executorB调度装载运行。我们故意没有给task2()的@Async指定线程池,但由于在Application里面通过配置注解@EnableAsync

开启了多线程任务特性,所以,spring框架为task2()也启用了默认的未经配置的线程池。

### Java `@Async` 注解自定义线程池配置及使用方法 #### 配置自定义线程池 为了使 `@Async` 使用特定的线程池而非 Spring 默认提供者,需先创建并配置一个 `TaskExecutor` Bean。这可以通过在任意 `@Configuration` 类中声明来完成。 ```java import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import java.util.concurrent.Executor; import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor; @Configuration public class AsyncConfig { @Bean(name = "myExecutor") public Executor taskExecutor() { ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor(); executor.setCorePoolSize(5); executor.setMaxPoolSize(10); executor.setQueueCapacity(25); executor.initialize(); return executor; } } ``` 上述代码片段展示了如何通过设置核心线程数、最大线程数以及队列容量来自定义线程池属性[^1]。 #### 应用 `@Async` 注解 一旦有了自定义线程池,在目标服务类的方法上应用 `@Async` 注解即可让其异步运行。需要注意的是,这里指定了要使用的线程池名称 `"myExecutor"` 来确保该方法由之前定义的任务执行器处理。 ```java import org.springframework.scheduling.annotation.Async; import org.springframework.stereotype.Service; @Service public class AsyncTest { @Async("myExecutor") public void executeAsync() { System.out.println(Thread.currentThread().getName()); System.out.println("Executing asynchronously"); } } ``` 当调用带有 `@Async` 的方法时,它将在不同的线程上下文中被执行,并不会阻塞主线程直到操作完成。 此外,为了让应用程序识别这些配置,还需启用全局异步支持: ```java import org.springframework.scheduling.annotation.EnableAsync; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; @SpringBootApplication @EnableAsync public class Application { public static void main(String[] args) { SpringApplication.run(Application.class, args); } } ``` 这样就完成了整个流程——从配置到实际运用 `@Async` 和自定义线程池的工作方式[^2]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

zhangphil

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值