Spring Boot使用@Async和自定义线程池实现异步调用

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/chengqiuming/article/details/83684429

一 新建依赖

<dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter</artifactId>
    </dependency>

    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-test</artifactId>
        <scope>test</scope>
    </dependency>

    <dependency>
        <groupId>org.projectlombok</groupId>
        <artifactId>lombok</artifactId>
        <version>1.16.20</version>
        <scope>provided</scope>
    </dependency>

</dependencies>

二 定义异步任务

package com.didispace.async;

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

import java.util.Random;

@Slf4j
@Component
public class Task {

    public static Random random = new Random();

    //在@Async注解中指定线程池名
    @Async("taskExecutor")
    public void doTaskOne() throws Exception {
        log.info("开始做任务一");
        long start = System.currentTimeMillis();
        Thread.sleep(random.nextInt(10000));
        long end = System.currentTimeMillis();
        log.info("完成任务一,耗时:" + (end - start) + "毫秒");
    }

    @Async("taskExecutor")
    public void doTaskTwo() throws Exception {
        log.info("开始做任务二");
        long start = System.currentTimeMillis();
        Thread.sleep(random.nextInt(10000));
        long end = System.currentTimeMillis();
        log.info("完成任务二,耗时:" + (end - start) + "毫秒");
    }

    @Async("taskExecutor")
    public void doTaskThree() throws Exception {
        log.info("开始做任务三");
        long start = System.currentTimeMillis();
        Thread.sleep(random.nextInt(10000));
        long end = System.currentTimeMillis();
        log.info("完成任务三,耗时:" + (end - start) + "毫秒");
    }

}

三 启动类

package com.didispace;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;

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


@SpringBootApplication
public class Application {

    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }

    @EnableAsync
    @Configuration
    class TaskPoolConfig {

        @Bean("taskExecutor")
        public Executor taskExecutor() {
            ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
            executor.setCorePoolSize(10);  // 核心线程数10:线程池创建时候初始化的线程数
            executor.setMaxPoolSize(20);   // 最大线程数20:线程池最大的线程数,只有在缓冲队列满了之后才会申请超过核心线程数的线程
            executor.setQueueCapacity(200); // 缓冲队列200:用来缓冲执行任务的队列
            executor.setKeepAliveSeconds(60);  // 允许线程的空闲时间60秒:当超过了核心线程出之外的线程在空闲时间到达之后会被销毁
            executor.setThreadNamePrefix("taskExecutor-");  // 线程池名的前缀:设置好了之后可以方便我们定位处理任务所在的线程池

            // 线程池对拒绝任务的处理策略:这里采用了CallerRunsPolicy策略,
            // 当线程池没有处理能力的时候,该策略会直接在 execute 方法的调用线程中运行被拒绝的任务;
            // 如果执行程序已关闭,则会丢弃该任务
            executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
            return executor;
        }
    }

}

四 定义测试类

package com.didispace;

import com.didispace.async.Task;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;


@RunWith(SpringJUnit4ClassRunner.class)
@SpringBootTest
public class ApplicationTests {

    @Autowired
    private Task task;

    @Test
    public void test() throws Exception {

        task.doTaskOne();
        task.doTaskTwo();
        task.doTaskThree();

        Thread.currentThread().join();
    }

}

五 测试结果

执行上面的单元测试,我们可以在控制台中看到所有输出的线程名前都是之前我们定义的线程池前缀名开始的,说明我们使用线程池来执行异步任务的试验成功了!

2018-11-03 09:55:30.377  INFO 20584 --- [ taskExecutor-1] com.didispace.async.Task                 : 开始做任务一
2018-11-03 09:55:30.430  INFO 20584 --- [ taskExecutor-2] com.didispace.async.Task                 : 开始做任务二
2018-11-03 09:55:30.431  INFO 20584 --- [ taskExecutor-3] com.didispace.async.Task                 : 开始做任务三
2018-11-03 09:55:31.281  INFO 20584 --- [ taskExecutor-2] com.didispace.async.Task                 : 完成任务二,耗时:851毫秒
2018-11-03 09:55:33.021  INFO 20584 --- [ taskExecutor-1] com.didispace.async.Task                 : 完成任务一,耗时:2643毫秒
2018-11-03 09:55:40.096  INFO 20584 --- [ taskExecutor-3] com.didispace.async.Task                 : 完成任务三,耗时:9665毫秒

六 参考 

https://blog.csdn.net/pozmckaoddb/article/details/51478017

http://blog.didispace.com/springbootasync-2/

猜你喜欢

转载自blog.csdn.net/chengqiuming/article/details/83684429