Java创建线程池使用EnableAsync实现多线程

前言

        我们在使用多线程的时候,往往需要创建Thread类,或者实现Runnable接口,如果要使用到线程池,我们还需要来创建Executors,在使用spring中,已经给我们做了很好的支持。只要要@EnableAsync就可以使用多线程。使用@Async就可以定义一个线程任务。通过spring给我们提供的ThreadPoolTaskExecutor就可以使用线程池。

        默认情况下,Spring将搜索相关的线程池定义:要么在上下文中搜索唯一的TaskExecutor bean,要么搜索名为“taskExecutor”的Executor bean。如果两者都无法解析,则将使用SimpleAsyncTaskExecutor来处理异步方法调用。

配置文件

        配置文件我这里用的是yml文件管理的,增加的配置如下:

#线程池配置
executor:
  config:
    thread-pool:
      core-pool-size: 5  #核心线程数
      max-pool-size: 30  #最大线程数
      queue-capacity: 99999  #队列大小

配置类

        @Configuration用于定义配置类,被注解的类内部包含有一个或多个被@Bean注解的方法,这些方法将会被AnnotationConfigApplicationContext或AnnotationConfigWebApplicationContext类进行扫描,并用于构建bean定义,初始化Spring容器。

        @EnableAsync开始对异步任务的支持 。 

@Configuration
@EnableAsync
public class ExecutorConfig {

    @Value("${executor.config.thread-pool.core-pool-size}")
    private Integer corePoolSize;

    @Value("${executor.config.thread-pool.max-pool-size}")
    private Integer maxPoolSize;

    @Value("${executor.config.thread-pool.queue-capacity}")
    private Integer queueCapacity;

    @Bean("testExecutor")
    public Executor asyncServiceExecutor() {
        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
        //配置核心线程数
        executor.setCorePoolSize(corePoolSize);
        //配置最大线程数
        executor.setMaxPoolSize(maxPoolSize);
        //配置队列大小
        executor.setQueueCapacity(queueCapacity);
        //配置线程池中的线程的名称前缀
        executor.setThreadNamePrefix("audit-service-");

        // rejection-policy:当pool已经达到max size的时候,如何处理新任务
        // CALLER_RUNS:不在新线程中执行任务,而是有调用者所在的线程来执行
        executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
        //执行初始化
        executor.initialize();
        return executor;
    }
}

测试service

        测试方法不能放在controller里面,最好是放在service或者Component里面,不然无法实现异步调试。

@Service
public class ThreadPoolTaskService {
    private Logger logger = LoggerFactory.getLogger(this.getClass());

    @Async("testExecutor")
    public void test1() throws InterruptedException {
        logger.info("--------start-test1------------");
        Thread.sleep(5000); // 模拟耗时
        logger.info("--------end-test1------------");
    }

    @Async("testExecutor")
    public void test2() throws InterruptedException {

        logger.info("--------start-test2------------");
        Thread.sleep(2000); // 模拟耗时
        logger.info("--------end-test2------------");

    }

}

        @Async注解来声明一个或多个异步任务,可以加在方法或者类上,加在类上表示这整个类都是使用这个自定义线程池进行操作。

测试controller

    @GetMapping("testTask")
    public void test()throws Exception{
        taskService.test1();
        taskService.test2();
    }

        接着我们可以创建control类@Autowired这个service并且调用这其中两个方法,进行连续调用,会发现运行结果是:

2021-07-15 13:55:59.587  INFO 35488 --- [audit-service-2] .luke.audit.config.ThreadPoolTaskService : --------start-test2------------
2021-07-15 13:55:59.588  INFO 35488 --- [audit-service-5] .luke.audit.config.ThreadPoolTaskService : --------start-test1------------
2021-07-15 13:56:01.597  INFO 35488 --- [audit-service-2] .luke.audit.config.ThreadPoolTaskService : --------end-test2------------
2021-07-15 13:56:04.592  INFO 35488 --- [audit-service-5] .luke.audit.config.ThreadPoolTaskService : --------end-test1------------

这里我们就是配置成功了。

总结

一、异步方法使用static修饰 二、异步类没有使用@Component注解(或其他注解)导致spring无法扫描到异步类 三、异步方法不能与异步方法在同一个类中 四、类中需要使用@Autowired或@Resource等注解自动注入,不能自己手动new对象 五、如果使用SpringBoot框架必须在启动类中增加@EnableAsync注解 六、在Async 方法上标注@Transactional是没用的。 在Async 方法调用的方法上标注@Transactional 有效。 七、调用被@Async标记的方法的调用者不能和被调用的方法在同一类中不然不会起作用!!!!!!! 八、使用@Async时要求是不能有返回值的不然会报错的 因为异步要求是不关心结果的

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

文章由极客之家整理,本文链接:https://www.bmabk.com/index.php/post/4487.html

(0)
小半的头像小半

相关推荐

极客之家——专业性很强的中文编程技术网站,欢迎收藏到浏览器,订阅我们!